vendor: github.com/Masterminds/semver/v3 v3.4.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
@@ -3,7 +3,7 @@ module github.com/docker/buildx
|
|||||||
go 1.23.0
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver/v3 v3.2.1
|
github.com/Masterminds/semver/v3 v3.4.0
|
||||||
github.com/Microsoft/go-winio v0.6.2
|
github.com/Microsoft/go-winio v0.6.2
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.27.27
|
github.com/aws/aws-sdk-go-v2/config v1.27.27
|
||||||
github.com/compose-spec/compose-go/v2 v2.7.2-0.20250703132301-891fce532a51 // main
|
github.com/compose-spec/compose-go/v2 v2.7.2-0.20250703132301-891fce532a51 // main
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h
|
|||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
|
github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
|
||||||
|
|||||||
+55
-1
@@ -1,5 +1,59 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 3.4.0 (2025-06-27)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #268: Added property to Constraints to include prereleases for Check and Validate
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #263: Updated Go testing for 1.24, 1.23, and 1.22
|
||||||
|
- #269: Updated the error message handling for message case and wrapping errors
|
||||||
|
- #266: Restore the ability to have leading 0's when parsing with NewVersion.
|
||||||
|
Opt-out of this by setting CoerceNewVersion to false.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #257: Fixed the CodeQL link (thanks @dmitris)
|
||||||
|
- #262: Restored detailed errors when failed to parse with NewVersion. Opt-out
|
||||||
|
of this by setting DetailedNewVersionErrors to false for faster performance.
|
||||||
|
- #267: Handle pre-releases for an "and" group if one constraint includes them
|
||||||
|
|
||||||
|
## 3.3.1 (2024-11-19)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #253: Fix for allowing some version that were invalid
|
||||||
|
|
||||||
|
## 3.3.0 (2024-08-27)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #238: Add LessThanEqual and GreaterThanEqual functions (thanks @grosser)
|
||||||
|
- #213: nil version equality checking (thanks @KnutZuidema)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #241: Simplify StrictNewVersion parsing (thanks @grosser)
|
||||||
|
- Testing support up through Go 1.23
|
||||||
|
- Minimum version set to 1.21 as this is what's tested now
|
||||||
|
- Fuzz testing now supports caching
|
||||||
|
|
||||||
|
## 3.2.1 (2023-04-10)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #198: Improved testing around pre-release names
|
||||||
|
- #200: Improved code scanning with addition of CodeQL
|
||||||
|
- #201: Testing now includes Go 1.20. Go 1.17 has been dropped
|
||||||
|
- #202: Migrated Fuzz testing to Go built-in Fuzzing. CI runs daily
|
||||||
|
- #203: Docs updated for security details
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #199: Fixed issue with range transformations
|
||||||
|
|
||||||
## 3.2.0 (2022-11-28)
|
## 3.2.0 (2022-11-28)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -109,7 +163,7 @@ functions. These are described in the added and changed sections below.
|
|||||||
- #78: Fix unchecked error in example code (thanks @ravron)
|
- #78: Fix unchecked error in example code (thanks @ravron)
|
||||||
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
- #97: Fixed copyright file for proper display on GitHub
|
- #97: Fixed copyright file for proper display on GitHub
|
||||||
- #107: Fix handling prerelease when sorting alphanum and num
|
- #107: Fix handling prerelease when sorting alphanum and num
|
||||||
- #109: Fixed where Validate sometimes returns wrong message on error
|
- #109: Fixed where Validate sometimes returns wrong message on error
|
||||||
|
|
||||||
## 1.4.2 (2018-04-10)
|
## 1.4.2 (2018-04-10)
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ test-cover:
|
|||||||
.PHONY: fuzz
|
.PHONY: fuzz
|
||||||
fuzz:
|
fuzz:
|
||||||
@echo "==> Running Fuzz Tests"
|
@echo "==> Running Fuzz Tests"
|
||||||
|
go env GOCACHE
|
||||||
go test -fuzz=FuzzNewVersion -fuzztime=15s .
|
go test -fuzz=FuzzNewVersion -fuzztime=15s .
|
||||||
go test -fuzz=FuzzStrictNewVersion -fuzztime=15s .
|
go test -fuzz=FuzzStrictNewVersion -fuzztime=15s .
|
||||||
go test -fuzz=FuzzNewConstraint -fuzztime=15s .
|
go test -fuzz=FuzzNewConstraint -fuzztime=15s .
|
||||||
@@ -27,4 +28,4 @@ $(GOLANGCI_LINT):
|
|||||||
# Install golangci-lint. The configuration for it is in the .golangci.yml
|
# Install golangci-lint. The configuration for it is in the .golangci.yml
|
||||||
# file in the root of the repository
|
# file in the root of the repository
|
||||||
echo ${GOPATH}
|
echo ${GOPATH}
|
||||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1
|
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.56.2
|
||||||
|
|||||||
+31
-15
@@ -13,12 +13,9 @@ Active](https://masterminds.github.io/stability/active.svg)](https://masterminds
|
|||||||
[](https://pkg.go.dev/github.com/Masterminds/semver/v3)
|
[](https://pkg.go.dev/github.com/Masterminds/semver/v3)
|
||||||
[](https://goreportcard.com/report/github.com/Masterminds/semver)
|
[](https://goreportcard.com/report/github.com/Masterminds/semver)
|
||||||
|
|
||||||
If you are looking for a command line tool for version comparisons please see
|
|
||||||
[vert](https://github.com/Masterminds/vert) which uses this library.
|
|
||||||
|
|
||||||
## Package Versions
|
## Package Versions
|
||||||
|
|
||||||
Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version.
|
Note, import `github.com/Masterminds/semver/v3` to use the latest version.
|
||||||
|
|
||||||
There are three major versions fo the `semver` package.
|
There are three major versions fo the `semver` package.
|
||||||
|
|
||||||
@@ -53,6 +50,18 @@ other versions, convert the version back into a string, and get the original
|
|||||||
string. Getting the original string is useful if the semantic version was coerced
|
string. Getting the original string is useful if the semantic version was coerced
|
||||||
into a valid form.
|
into a valid form.
|
||||||
|
|
||||||
|
There are package level variables that affect how `NewVersion` handles parsing.
|
||||||
|
|
||||||
|
- `CoerceNewVersion` is `true` by default. When set to `true` it coerces non-compliant
|
||||||
|
versions into SemVer. For example, allowing a leading 0 in a major, minor, or patch
|
||||||
|
part. This enables the use of CalVer in versions even when not compliant with SemVer.
|
||||||
|
When set to `false` less coercion work is done.
|
||||||
|
- `DetailedNewVersionErrors` provides more detailed errors. It only has an affect when
|
||||||
|
`CoerceNewVersion` is set to `false`. When `DetailedNewVersionErrors` is set to `true`
|
||||||
|
it can provide some more insight into why a version is invalid. Setting
|
||||||
|
`DetailedNewVersionErrors` to `false` is faster on performance but provides less
|
||||||
|
detailed error messages if a version fails to parse.
|
||||||
|
|
||||||
## Sorting Semantic Versions
|
## Sorting Semantic Versions
|
||||||
|
|
||||||
A set of versions can be sorted using the `sort` package from the standard library.
|
A set of versions can be sorted using the `sort` package from the standard library.
|
||||||
@@ -80,12 +89,12 @@ There are two methods for comparing versions. One uses comparison methods on
|
|||||||
differences to notes between these two methods of comparison.
|
differences to notes between these two methods of comparison.
|
||||||
|
|
||||||
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
||||||
and others it will follow the specification and always include prereleases
|
and others it will follow the specification and always include pre-releases
|
||||||
within the comparison. It will provide an answer that is valid with the
|
within the comparison. It will provide an answer that is valid with the
|
||||||
comparison section of the spec at https://semver.org/#spec-item-11
|
comparison section of the spec at https://semver.org/#spec-item-11
|
||||||
2. When constraint checking is used for checks or validation it will follow a
|
2. When constraint checking is used for checks or validation it will follow a
|
||||||
different set of rules that are common for ranges with tools like npm/js
|
different set of rules that are common for ranges with tools like npm/js
|
||||||
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
and Rust/Cargo. This includes considering pre-releases to be invalid if the
|
||||||
ranges does not include one. If you want to have it include pre-releases a
|
ranges does not include one. If you want to have it include pre-releases a
|
||||||
simple solution is to include `-0` in your range.
|
simple solution is to include `-0` in your range.
|
||||||
3. Constraint ranges can have some complex rules including the shorthand use of
|
3. Constraint ranges can have some complex rules including the shorthand use of
|
||||||
@@ -113,7 +122,7 @@ v, err := semver.NewVersion("1.3")
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// Handle version not being parsable.
|
// Handle version not being parsable.
|
||||||
}
|
}
|
||||||
// Check if the version meets the constraints. The a variable will be true.
|
// Check if the version meets the constraints. The variable a will be true.
|
||||||
a := c.Check(v)
|
a := c.Check(v)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -137,20 +146,20 @@ The basic comparisons are:
|
|||||||
### Working With Prerelease Versions
|
### Working With Prerelease Versions
|
||||||
|
|
||||||
Pre-releases, for those not familiar with them, are used for software releases
|
Pre-releases, for those not familiar with them, are used for software releases
|
||||||
prior to stable or generally available releases. Examples of prereleases include
|
prior to stable or generally available releases. Examples of pre-releases include
|
||||||
development, alpha, beta, and release candidate releases. A prerelease may be
|
development, alpha, beta, and release candidate releases. A pre-release may be
|
||||||
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
||||||
order of precedence, prereleases come before their associated releases. In this
|
order of precedence, pre-releases come before their associated releases. In this
|
||||||
example `1.2.3-beta.1 < 1.2.3`.
|
example `1.2.3-beta.1 < 1.2.3`.
|
||||||
|
|
||||||
According to the Semantic Version specification prereleases may not be
|
According to the Semantic Version specification, pre-releases may not be
|
||||||
API compliant with their release counterpart. It says,
|
API compliant with their release counterpart. It says,
|
||||||
|
|
||||||
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
||||||
|
|
||||||
SemVer comparisons using constraints without a prerelease comparator will skip
|
SemVer's comparisons using constraints without a pre-release comparator will skip
|
||||||
prerelease versions. For example, `>=1.2.3` will skip prereleases when looking
|
pre-release versions. For example, `>=1.2.3` will skip pre-releases when looking
|
||||||
at a list of releases while `>=1.2.3-0` will evaluate and find prereleases.
|
at a list of releases while `>=1.2.3-0` will evaluate and find pre-releases.
|
||||||
|
|
||||||
The reason for the `0` as a pre-release version in the example comparison is
|
The reason for the `0` as a pre-release version in the example comparison is
|
||||||
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
||||||
@@ -163,6 +172,10 @@ means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case
|
|||||||
sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
|
sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
|
||||||
the spec specifies.
|
the spec specifies.
|
||||||
|
|
||||||
|
The `Constraints` instance returned from `semver.NewConstraint()` has a property
|
||||||
|
`IncludePrerelease` that, when set to true, will return prerelease versions when calls
|
||||||
|
to `Check()` and `Validate()` are made.
|
||||||
|
|
||||||
### Hyphen Range Comparisons
|
### Hyphen Range Comparisons
|
||||||
|
|
||||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
@@ -171,6 +184,9 @@ These look like:
|
|||||||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5`
|
* `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5`
|
||||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
||||||
|
|
||||||
|
Note that `1.2-1.4.5` without whitespace is parsed completely differently; it's
|
||||||
|
parsed as a single constraint `1.2.0` with _prerelease_ `1.4.5`.
|
||||||
|
|
||||||
### Wildcards In Comparisons
|
### Wildcards In Comparisons
|
||||||
|
|
||||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
@@ -250,7 +266,7 @@ or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
|||||||
Security is an important consideration for this project. The project currently
|
Security is an important consideration for this project. The project currently
|
||||||
uses the following tools to help discover security issues:
|
uses the following tools to help discover security issues:
|
||||||
|
|
||||||
* [CodeQL](https://github.com/Masterminds/semver)
|
* [CodeQL](https://codeql.github.com)
|
||||||
* [gosec](https://github.com/securego/gosec)
|
* [gosec](https://github.com/securego/gosec)
|
||||||
* Daily Fuzz testing
|
* Daily Fuzz testing
|
||||||
|
|
||||||
|
|||||||
+67
-60
@@ -12,6 +12,13 @@ import (
|
|||||||
// checked against.
|
// checked against.
|
||||||
type Constraints struct {
|
type Constraints struct {
|
||||||
constraints [][]*constraint
|
constraints [][]*constraint
|
||||||
|
containsPre []bool
|
||||||
|
|
||||||
|
// IncludePrerelease specifies if pre-releases should be included in
|
||||||
|
// the results. Note, if a constraint range has a prerelease than
|
||||||
|
// prereleases will be included for that AND group even if this is
|
||||||
|
// set to false.
|
||||||
|
IncludePrerelease bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConstraint returns a Constraints instance that a Version instance can
|
// NewConstraint returns a Constraints instance that a Version instance can
|
||||||
@@ -22,11 +29,10 @@ func NewConstraint(c string) (*Constraints, error) {
|
|||||||
c = rewriteRange(c)
|
c = rewriteRange(c)
|
||||||
|
|
||||||
ors := strings.Split(c, "||")
|
ors := strings.Split(c, "||")
|
||||||
or := make([][]*constraint, len(ors))
|
lenors := len(ors)
|
||||||
|
or := make([][]*constraint, lenors)
|
||||||
|
hasPre := make([]bool, lenors)
|
||||||
for k, v := range ors {
|
for k, v := range ors {
|
||||||
|
|
||||||
// TODO: Find a way to validate and fetch all the constraints in a simpler form
|
|
||||||
|
|
||||||
// Validate the segment
|
// Validate the segment
|
||||||
if !validConstraintRegex.MatchString(v) {
|
if !validConstraintRegex.MatchString(v) {
|
||||||
return nil, fmt.Errorf("improper constraint: %s", v)
|
return nil, fmt.Errorf("improper constraint: %s", v)
|
||||||
@@ -43,12 +49,22 @@ func NewConstraint(c string) (*Constraints, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If one of the constraints has a prerelease record this.
|
||||||
|
// This information is used when checking all in an "and"
|
||||||
|
// group to ensure they all check for prereleases.
|
||||||
|
if pc.con.pre != "" {
|
||||||
|
hasPre[k] = true
|
||||||
|
}
|
||||||
|
|
||||||
result[i] = pc
|
result[i] = pc
|
||||||
}
|
}
|
||||||
or[k] = result
|
or[k] = result
|
||||||
}
|
}
|
||||||
|
|
||||||
o := &Constraints{constraints: or}
|
o := &Constraints{
|
||||||
|
constraints: or,
|
||||||
|
containsPre: hasPre,
|
||||||
|
}
|
||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +73,10 @@ func (cs Constraints) Check(v *Version) bool {
|
|||||||
// TODO(mattfarina): For v4 of this library consolidate the Check and Validate
|
// TODO(mattfarina): For v4 of this library consolidate the Check and Validate
|
||||||
// functions as the underlying functions make that possible now.
|
// functions as the underlying functions make that possible now.
|
||||||
// loop over the ORs and check the inner ANDs
|
// loop over the ORs and check the inner ANDs
|
||||||
for _, o := range cs.constraints {
|
for i, o := range cs.constraints {
|
||||||
joy := true
|
joy := true
|
||||||
for _, c := range o {
|
for _, c := range o {
|
||||||
if check, _ := c.check(v); !check {
|
if check, _ := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); !check {
|
||||||
joy = false
|
joy = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -83,12 +99,12 @@ func (cs Constraints) Validate(v *Version) (bool, []error) {
|
|||||||
// Capture the prerelease message only once. When it happens the first time
|
// Capture the prerelease message only once. When it happens the first time
|
||||||
// this var is marked
|
// this var is marked
|
||||||
var prerelesase bool
|
var prerelesase bool
|
||||||
for _, o := range cs.constraints {
|
for i, o := range cs.constraints {
|
||||||
joy := true
|
joy := true
|
||||||
for _, c := range o {
|
for _, c := range o {
|
||||||
// Before running the check handle the case there the version is
|
// Before running the check handle the case there the version is
|
||||||
// a prerelease and the check is not searching for prereleases.
|
// a prerelease and the check is not searching for prereleases.
|
||||||
if c.con.pre == "" && v.pre != "" {
|
if !(cs.IncludePrerelease || cs.containsPre[i]) && v.pre != "" {
|
||||||
if !prerelesase {
|
if !prerelesase {
|
||||||
em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
e = append(e, em)
|
e = append(e, em)
|
||||||
@@ -98,7 +114,7 @@ func (cs Constraints) Validate(v *Version) (bool, []error) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if _, err := c.check(v); err != nil {
|
if _, err := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); err != nil {
|
||||||
e = append(e, err)
|
e = append(e, err)
|
||||||
joy = false
|
joy = false
|
||||||
}
|
}
|
||||||
@@ -227,8 +243,8 @@ type constraint struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if a version meets the constraint
|
// Check if a version meets the constraint
|
||||||
func (c *constraint) check(v *Version) (bool, error) {
|
func (c *constraint) check(v *Version, includePre bool) (bool, error) {
|
||||||
return constraintOps[c.origfunc](v, c)
|
return constraintOps[c.origfunc](v, c, includePre)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String prints an individual constraint into a string
|
// String prints an individual constraint into a string
|
||||||
@@ -236,7 +252,7 @@ func (c *constraint) string() string {
|
|||||||
return c.origfunc + c.orig
|
return c.origfunc + c.orig
|
||||||
}
|
}
|
||||||
|
|
||||||
type cfunc func(v *Version, c *constraint) (bool, error)
|
type cfunc func(v *Version, c *constraint, includePre bool) (bool, error)
|
||||||
|
|
||||||
func parseConstraint(c string) (*constraint, error) {
|
func parseConstraint(c string) (*constraint, error) {
|
||||||
if len(c) > 0 {
|
if len(c) > 0 {
|
||||||
@@ -272,7 +288,7 @@ func parseConstraint(c string) (*constraint, error) {
|
|||||||
|
|
||||||
// The constraintRegex should catch any regex parsing errors. So,
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
// we should never get here.
|
// we should never get here.
|
||||||
return nil, errors.New("constraint Parser Error")
|
return nil, errors.New("constraint parser error")
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.con = con
|
cs.con = con
|
||||||
@@ -290,7 +306,7 @@ func parseConstraint(c string) (*constraint, error) {
|
|||||||
|
|
||||||
// The constraintRegex should catch any regex parsing errors. So,
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
// we should never get here.
|
// we should never get here.
|
||||||
return nil, errors.New("constraint Parser Error")
|
return nil, errors.New("constraint parser error")
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := &constraint{
|
cs := &constraint{
|
||||||
@@ -305,16 +321,14 @@ func parseConstraint(c string) (*constraint, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constraint functions
|
// Constraint functions
|
||||||
func constraintNotEqual(v *Version, c *constraint) (bool, error) {
|
func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
|
if v.Prerelease() != "" && !includePre {
|
||||||
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
|
}
|
||||||
|
|
||||||
if c.dirty {
|
if c.dirty {
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.con.Major() != v.Major() {
|
if c.con.Major() != v.Major() {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@@ -345,12 +359,11 @@ func constraintNotEqual(v *Version, c *constraint) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func constraintGreaterThan(v *Version, c *constraint) (bool, error) {
|
func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,11 +404,10 @@ func constraintGreaterThan(v *Version, c *constraint) (bool, error) {
|
|||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func constraintLessThan(v *Version, c *constraint) (bool, error) {
|
func constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,12 +418,11 @@ func constraintLessThan(v *Version, c *constraint) (bool, error) {
|
|||||||
return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
|
return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) {
|
func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,11 +433,10 @@ func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) {
|
|||||||
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func constraintLessThanEqual(v *Version, c *constraint) (bool, error) {
|
func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,11 +465,10 @@ func constraintLessThanEqual(v *Version, c *constraint) (bool, error) {
|
|||||||
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
||||||
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
||||||
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
||||||
func constraintTilde(v *Version, c *constraint) (bool, error) {
|
func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,16 +496,15 @@ func constraintTilde(v *Version, c *constraint) (bool, error) {
|
|||||||
|
|
||||||
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
||||||
// it's a straight =
|
// it's a straight =
|
||||||
func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) {
|
func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.dirty {
|
if c.dirty {
|
||||||
return constraintTilde(v, c)
|
return constraintTilde(v, c, includePre)
|
||||||
}
|
}
|
||||||
|
|
||||||
eq := v.Equal(c.con)
|
eq := v.Equal(c.con)
|
||||||
@@ -516,11 +524,10 @@ func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) {
|
|||||||
// ^0.0.3 --> >=0.0.3 <0.0.4
|
// ^0.0.3 --> >=0.0.3 <0.0.4
|
||||||
// ^0.0 --> >=0.0.0 <0.1.0
|
// ^0.0 --> >=0.0.0 <0.1.0
|
||||||
// ^0 --> >=0.0.0 <1.0.0
|
// ^0 --> >=0.0.0 <1.0.0
|
||||||
func constraintCaret(v *Version, c *constraint) (bool, error) {
|
func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
// The existence of prereleases is checked at the group level and passed in.
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
// Exit early if the version has a prerelease but those are to be ignored.
|
||||||
// more details.
|
if v.Prerelease() != "" && !includePre {
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+185
-36
@@ -14,32 +14,52 @@ import (
|
|||||||
// The compiled version of the regex created at init() is cached here so it
|
// The compiled version of the regex created at init() is cached here so it
|
||||||
// only needs to be created once.
|
// only needs to be created once.
|
||||||
var versionRegex *regexp.Regexp
|
var versionRegex *regexp.Regexp
|
||||||
|
var looseVersionRegex *regexp.Regexp
|
||||||
|
|
||||||
|
// CoerceNewVersion sets if leading 0's are allowd in the version part. Leading 0's are
|
||||||
|
// not allowed in a valid semantic version. When set to true, NewVersion will coerce
|
||||||
|
// leading 0's into a valid version.
|
||||||
|
var CoerceNewVersion = true
|
||||||
|
|
||||||
|
// DetailedNewVersionErrors specifies if detailed errors are returned from the NewVersion
|
||||||
|
// function. This is used when CoerceNewVersion is set to false. If set to false
|
||||||
|
// ErrInvalidSemVer is returned for an invalid version. This does not apply to
|
||||||
|
// StrictNewVersion. Setting this function to false returns errors more quickly.
|
||||||
|
var DetailedNewVersionErrors = true
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrInvalidSemVer is returned a version is found to be invalid when
|
// ErrInvalidSemVer is returned a version is found to be invalid when
|
||||||
// being parsed.
|
// being parsed.
|
||||||
ErrInvalidSemVer = errors.New("Invalid Semantic Version")
|
ErrInvalidSemVer = errors.New("invalid semantic version")
|
||||||
|
|
||||||
// ErrEmptyString is returned when an empty string is passed in for parsing.
|
// ErrEmptyString is returned when an empty string is passed in for parsing.
|
||||||
ErrEmptyString = errors.New("Version string empty")
|
ErrEmptyString = errors.New("version string empty")
|
||||||
|
|
||||||
// ErrInvalidCharacters is returned when invalid characters are found as
|
// ErrInvalidCharacters is returned when invalid characters are found as
|
||||||
// part of a version
|
// part of a version
|
||||||
ErrInvalidCharacters = errors.New("Invalid characters in version")
|
ErrInvalidCharacters = errors.New("invalid characters in version")
|
||||||
|
|
||||||
// ErrSegmentStartsZero is returned when a version segment starts with 0.
|
// ErrSegmentStartsZero is returned when a version segment starts with 0.
|
||||||
// This is invalid in SemVer.
|
// This is invalid in SemVer.
|
||||||
ErrSegmentStartsZero = errors.New("Version segment starts with 0")
|
ErrSegmentStartsZero = errors.New("version segment starts with 0")
|
||||||
|
|
||||||
// ErrInvalidMetadata is returned when the metadata is an invalid format
|
// ErrInvalidMetadata is returned when the metadata is an invalid format
|
||||||
ErrInvalidMetadata = errors.New("Invalid Metadata string")
|
ErrInvalidMetadata = errors.New("invalid metadata string")
|
||||||
|
|
||||||
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
|
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
|
||||||
ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
|
ErrInvalidPrerelease = errors.New("invalid prerelease string")
|
||||||
)
|
)
|
||||||
|
|
||||||
// semVerRegex is the regular expression used to parse a semantic version.
|
// semVerRegex is the regular expression used to parse a semantic version.
|
||||||
const semVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
|
// This is not the official regex from the semver spec. It has been modified to allow for loose handling
|
||||||
|
// where versions like 2.1 are detected.
|
||||||
|
const semVerRegex string = `v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?` +
|
||||||
|
`(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` +
|
||||||
|
`(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?`
|
||||||
|
|
||||||
|
// looseSemVerRegex is a regular expression that lets invalid semver expressions through
|
||||||
|
// with enough detail that certain errors can be checked for.
|
||||||
|
const looseSemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
|
||||||
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
@@ -53,6 +73,7 @@ type Version struct {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
versionRegex = regexp.MustCompile("^" + semVerRegex + "$")
|
versionRegex = regexp.MustCompile("^" + semVerRegex + "$")
|
||||||
|
looseVersionRegex = regexp.MustCompile("^" + looseSemVerRegex + "$")
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -83,22 +104,23 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||||||
original: v,
|
original: v,
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for prerelease or build metadata
|
// Extract build metadata
|
||||||
var extra []string
|
if strings.Contains(parts[2], "+") {
|
||||||
if strings.ContainsAny(parts[2], "-+") {
|
extra := strings.SplitN(parts[2], "+", 2)
|
||||||
// Start with the build metadata first as it needs to be on the right
|
sv.metadata = extra[1]
|
||||||
extra = strings.SplitN(parts[2], "+", 2)
|
parts[2] = extra[0]
|
||||||
if len(extra) > 1 {
|
if err := validateMetadata(sv.metadata); err != nil {
|
||||||
// build metadata found
|
return nil, err
|
||||||
sv.metadata = extra[1]
|
|
||||||
parts[2] = extra[0]
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extra = strings.SplitN(parts[2], "-", 2)
|
// Extract build prerelease
|
||||||
if len(extra) > 1 {
|
if strings.Contains(parts[2], "-") {
|
||||||
// prerelease found
|
extra := strings.SplitN(parts[2], "-", 2)
|
||||||
sv.pre = extra[1]
|
sv.pre = extra[1]
|
||||||
parts[2] = extra[0]
|
parts[2] = extra[0]
|
||||||
|
if err := validatePrerelease(sv.pre); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +136,7 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the major, minor, and patch elements onto the returned Version
|
// Extract major, minor, and patch
|
||||||
var err error
|
var err error
|
||||||
sv.major, err = strconv.ParseUint(parts[0], 10, 64)
|
sv.major, err = strconv.ParseUint(parts[0], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -131,10 +153,70 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// No prerelease or build metadata found so returning now as a fastpath.
|
return sv, nil
|
||||||
if sv.pre == "" && sv.metadata == "" {
|
}
|
||||||
return sv, nil
|
|
||||||
|
// NewVersion parses a given version and returns an instance of Version or
|
||||||
|
// an error if unable to parse the version. If the version is SemVer-ish it
|
||||||
|
// attempts to convert it to SemVer. If you want to validate it was a strict
|
||||||
|
// semantic version at parse time see StrictNewVersion().
|
||||||
|
func NewVersion(v string) (*Version, error) {
|
||||||
|
if CoerceNewVersion {
|
||||||
|
return coerceNewVersion(v)
|
||||||
}
|
}
|
||||||
|
m := versionRegex.FindStringSubmatch(v)
|
||||||
|
if m == nil {
|
||||||
|
|
||||||
|
// Disabling detailed errors is first so that it is in the fast path.
|
||||||
|
if !DetailedNewVersionErrors {
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for specific errors with the semver string and return a more detailed
|
||||||
|
// error.
|
||||||
|
m = looseVersionRegex.FindStringSubmatch(v)
|
||||||
|
if m == nil {
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
err := validateVersion(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := &Version{
|
||||||
|
metadata: m[5],
|
||||||
|
pre: m[4],
|
||||||
|
original: v,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
sv.major, err = strconv.ParseUint(m[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[2] != "" {
|
||||||
|
sv.minor, err = strconv.ParseUint(m[2], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sv.minor = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[3] != "" {
|
||||||
|
sv.patch, err = strconv.ParseUint(m[3], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sv.patch = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform some basic due diligence on the extra parts to ensure they are
|
||||||
|
// valid.
|
||||||
|
|
||||||
if sv.pre != "" {
|
if sv.pre != "" {
|
||||||
if err = validatePrerelease(sv.pre); err != nil {
|
if err = validatePrerelease(sv.pre); err != nil {
|
||||||
@@ -151,12 +233,8 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||||||
return sv, nil
|
return sv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVersion parses a given version and returns an instance of Version or
|
func coerceNewVersion(v string) (*Version, error) {
|
||||||
// an error if unable to parse the version. If the version is SemVer-ish it
|
m := looseVersionRegex.FindStringSubmatch(v)
|
||||||
// attempts to convert it to SemVer. If you want to validate it was a strict
|
|
||||||
// semantic version at parse time see StrictNewVersion().
|
|
||||||
func NewVersion(v string) (*Version, error) {
|
|
||||||
m := versionRegex.FindStringSubmatch(v)
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil, ErrInvalidSemVer
|
return nil, ErrInvalidSemVer
|
||||||
}
|
}
|
||||||
@@ -170,13 +248,13 @@ func NewVersion(v string) (*Version, error) {
|
|||||||
var err error
|
var err error
|
||||||
sv.major, err = strconv.ParseUint(m[1], 10, 64)
|
sv.major, err = strconv.ParseUint(m[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m[2] != "" {
|
if m[2] != "" {
|
||||||
sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64)
|
sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sv.minor = 0
|
sv.minor = 0
|
||||||
@@ -185,7 +263,7 @@ func NewVersion(v string) (*Version, error) {
|
|||||||
if m[3] != "" {
|
if m[3] != "" {
|
||||||
sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64)
|
sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
return nil, fmt.Errorf("error parsing version segment: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sv.patch = 0
|
sv.patch = 0
|
||||||
@@ -381,15 +459,31 @@ func (v *Version) LessThan(o *Version) bool {
|
|||||||
return v.Compare(o) < 0
|
return v.Compare(o) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LessThanEqual tests if one version is less or equal than another one.
|
||||||
|
func (v *Version) LessThanEqual(o *Version) bool {
|
||||||
|
return v.Compare(o) <= 0
|
||||||
|
}
|
||||||
|
|
||||||
// GreaterThan tests if one version is greater than another one.
|
// GreaterThan tests if one version is greater than another one.
|
||||||
func (v *Version) GreaterThan(o *Version) bool {
|
func (v *Version) GreaterThan(o *Version) bool {
|
||||||
return v.Compare(o) > 0
|
return v.Compare(o) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GreaterThanEqual tests if one version is greater or equal than another one.
|
||||||
|
func (v *Version) GreaterThanEqual(o *Version) bool {
|
||||||
|
return v.Compare(o) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
// Equal tests if two versions are equal to each other.
|
// Equal tests if two versions are equal to each other.
|
||||||
// Note, versions can be equal with different metadata since metadata
|
// Note, versions can be equal with different metadata since metadata
|
||||||
// is not considered part of the comparable version.
|
// is not considered part of the comparable version.
|
||||||
func (v *Version) Equal(o *Version) bool {
|
func (v *Version) Equal(o *Version) bool {
|
||||||
|
if v == o {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v == nil || o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return v.Compare(o) == 0
|
return v.Compare(o) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,7 +706,9 @@ func containsOnly(s string, comp string) bool {
|
|||||||
func validatePrerelease(p string) error {
|
func validatePrerelease(p string) error {
|
||||||
eparts := strings.Split(p, ".")
|
eparts := strings.Split(p, ".")
|
||||||
for _, p := range eparts {
|
for _, p := range eparts {
|
||||||
if containsOnly(p, num) {
|
if p == "" {
|
||||||
|
return ErrInvalidPrerelease
|
||||||
|
} else if containsOnly(p, num) {
|
||||||
if len(p) > 1 && p[0] == '0' {
|
if len(p) > 1 && p[0] == '0' {
|
||||||
return ErrSegmentStartsZero
|
return ErrSegmentStartsZero
|
||||||
}
|
}
|
||||||
@@ -631,9 +727,62 @@ func validatePrerelease(p string) error {
|
|||||||
func validateMetadata(m string) error {
|
func validateMetadata(m string) error {
|
||||||
eparts := strings.Split(m, ".")
|
eparts := strings.Split(m, ".")
|
||||||
for _, p := range eparts {
|
for _, p := range eparts {
|
||||||
if !containsOnly(p, allowed) {
|
if p == "" {
|
||||||
|
return ErrInvalidMetadata
|
||||||
|
} else if !containsOnly(p, allowed) {
|
||||||
return ErrInvalidMetadata
|
return ErrInvalidMetadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateVersion checks for common validation issues but may not catch all errors
|
||||||
|
func validateVersion(m []string) error {
|
||||||
|
var err error
|
||||||
|
var v string
|
||||||
|
if m[1] != "" {
|
||||||
|
if len(m[1]) > 1 && m[1][0] == '0' {
|
||||||
|
return ErrSegmentStartsZero
|
||||||
|
}
|
||||||
|
_, err = strconv.ParseUint(m[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[2] != "" {
|
||||||
|
v = strings.TrimPrefix(m[2], ".")
|
||||||
|
if len(v) > 1 && v[0] == '0' {
|
||||||
|
return ErrSegmentStartsZero
|
||||||
|
}
|
||||||
|
_, err = strconv.ParseUint(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[3] != "" {
|
||||||
|
v = strings.TrimPrefix(m[3], ".")
|
||||||
|
if len(v) > 1 && v[0] == '0' {
|
||||||
|
return ErrSegmentStartsZero
|
||||||
|
}
|
||||||
|
_, err = strconv.ParseUint(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing version segment: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[5] != "" {
|
||||||
|
if err = validatePrerelease(m[5]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[8] != "" {
|
||||||
|
if err = validateMetadata(m[8]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
github.com/Azure/go-ansiterm
|
github.com/Azure/go-ansiterm
|
||||||
github.com/Azure/go-ansiterm/winterm
|
github.com/Azure/go-ansiterm/winterm
|
||||||
# github.com/Masterminds/semver/v3 v3.2.1
|
# github.com/Masterminds/semver/v3 v3.4.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.21
|
||||||
github.com/Masterminds/semver/v3
|
github.com/Masterminds/semver/v3
|
||||||
# github.com/Microsoft/go-winio v0.6.2
|
# github.com/Microsoft/go-winio v0.6.2
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
|
|||||||
Reference in New Issue
Block a user