mirror of
https://github.com/containers/skopeo.git
synced 2025-09-14 13:59:44 +00:00
add kubasobon:semver changes
use single semver constraint Signed-off-by: Hussein Firas <hussein.firas@loveholidays.com> Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
committed by
Miloslav Trmač
parent
695538a31a
commit
177d4adb20
@@ -12,6 +12,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver/v3"
|
||||||
commonFlag "github.com/containers/common/pkg/flag"
|
commonFlag "github.com/containers/common/pkg/flag"
|
||||||
"github.com/containers/common/pkg/retry"
|
"github.com/containers/common/pkg/retry"
|
||||||
"github.com/containers/image/v5/copy"
|
"github.com/containers/image/v5/copy"
|
||||||
@@ -71,6 +72,7 @@ type tlsVerifyConfig struct {
|
|||||||
type registrySyncConfig struct {
|
type registrySyncConfig struct {
|
||||||
Images map[string][]string // Images map images name to slices with the images' references (tags, digests)
|
Images map[string][]string // Images map images name to slices with the images' references (tags, digests)
|
||||||
ImagesByTagRegex map[string]string `yaml:"images-by-tag-regex"` // Images map images name to regular expression with the images' tags
|
ImagesByTagRegex map[string]string `yaml:"images-by-tag-regex"` // Images map images name to regular expression with the images' tags
|
||||||
|
ImagesBySemver map[string]string `yaml:"images-by-semver"` // ImagesBySemver maps a repository to a semver constraint (e.g. '>=3.14') to match images' tags to
|
||||||
Credentials types.DockerAuthConfig // Username and password used to authenticate with the registry
|
Credentials types.DockerAuthConfig // Username and password used to authenticate with the registry
|
||||||
TLSVerify tlsVerifyConfig `yaml:"tls-verify"` // TLS verification mode (enabled by default)
|
TLSVerify tlsVerifyConfig `yaml:"tls-verify"` // TLS verification mode (enabled by default)
|
||||||
CertDir string `yaml:"cert-dir"` // Path to the TLS certificates of the registry
|
CertDir string `yaml:"cert-dir"` // Path to the TLS certificates of the registry
|
||||||
@@ -304,6 +306,14 @@ func imagesToCopyFromRegistry(registryName string, cfg registrySyncConfig, sourc
|
|||||||
serverCtx.DockerAuthConfig = &cfg.Credentials
|
serverCtx.DockerAuthConfig = &cfg.Credentials
|
||||||
}
|
}
|
||||||
var repoDescList []repoDescriptor
|
var repoDescList []repoDescriptor
|
||||||
|
|
||||||
|
if len(cfg.Images) == 0 && len(cfg.ImagesByTagRegex) == 0 && len(cfg.ImagesBySemver) == 0 {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"registry": registryName,
|
||||||
|
}).Warn("No images specified for registry")
|
||||||
|
return repoDescList, nil
|
||||||
|
}
|
||||||
|
|
||||||
for imageName, refs := range cfg.Images {
|
for imageName, refs := range cfg.Images {
|
||||||
repoLogger := logrus.WithFields(logrus.Fields{
|
repoLogger := logrus.WithFields(logrus.Fields{
|
||||||
"repo": imageName,
|
"repo": imageName,
|
||||||
@@ -368,63 +378,146 @@ func imagesToCopyFromRegistry(registryName string, cfg registrySyncConfig, sourc
|
|||||||
Context: serverCtx})
|
Context: serverCtx})
|
||||||
}
|
}
|
||||||
|
|
||||||
for imageName, tagRegex := range cfg.ImagesByTagRegex {
|
// include repository descriptors for cfg.ImagesByTagRegex
|
||||||
repoLogger := logrus.WithFields(logrus.Fields{
|
{
|
||||||
"repo": imageName,
|
filterCollection, err := tagRegexFilterCollection(cfg.ImagesByTagRegex)
|
||||||
"registry": registryName,
|
|
||||||
})
|
|
||||||
repoRef, err := parseRepositoryReference(fmt.Sprintf("%s/%s", registryName, imageName))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
repoLogger.Error("Error parsing repository name, skipping")
|
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
continue
|
} else {
|
||||||
|
additionalRepoDescList := filterSourceReferences(serverCtx, registryName, filterCollection)
|
||||||
|
repoDescList = append(repoDescList, additionalRepoDescList...)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
repoLogger.Info("Processing repo")
|
// include repository descriptors for cfg.ImagesBySemver
|
||||||
|
{
|
||||||
var sourceReferences []types.ImageReference
|
filterCollection, err := semverFilterCollection(cfg.ImagesBySemver)
|
||||||
|
|
||||||
tagReg, err := regexp.Compile(tagRegex)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
repoLogger.WithFields(logrus.Fields{
|
|
||||||
"regex": tagRegex,
|
|
||||||
}).Error("Error parsing regex, skipping")
|
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
continue
|
} else {
|
||||||
|
additionalRepoDescList := filterSourceReferences(serverCtx, registryName, filterCollection)
|
||||||
|
repoDescList = append(repoDescList, additionalRepoDescList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoLogger.Info("Querying registry for image tags")
|
|
||||||
allSourceReferences, err := imagesToCopyFromRepo(serverCtx, repoRef)
|
|
||||||
if err != nil {
|
|
||||||
repoLogger.Error("Error processing repo, skipping")
|
|
||||||
logrus.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
repoLogger.Infof("Start filtering using the regular expression: %v", tagRegex)
|
|
||||||
for _, sReference := range allSourceReferences {
|
|
||||||
tagged, isTagged := sReference.DockerReference().(reference.Tagged)
|
|
||||||
if !isTagged {
|
|
||||||
repoLogger.Errorf("Internal error, reference %s does not have a tag, skipping", sReference.DockerReference())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if tagReg.MatchString(tagged.Tag()) {
|
|
||||||
sourceReferences = append(sourceReferences, sReference)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sourceReferences) == 0 {
|
|
||||||
repoLogger.Warnf("No refs to sync found")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
repoDescList = append(repoDescList, repoDescriptor{
|
|
||||||
ImageRefs: sourceReferences,
|
|
||||||
Context: serverCtx})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return repoDescList, nil
|
return repoDescList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filterFunc is a function used to limit the initial set of image references
|
||||||
|
// using tags, patterns, semver, etc.
|
||||||
|
type filterFunc func(*logrus.Entry, types.ImageReference) bool
|
||||||
|
|
||||||
|
// filterCollection is a map of repository names to filter functions.
|
||||||
|
type filterCollection map[string]filterFunc
|
||||||
|
|
||||||
|
// filterSourceReferences lists tags for images specified in the collection and
|
||||||
|
// filters them using assigned filter functions.
|
||||||
|
// It returns a list of repoDescriptors.
|
||||||
|
func filterSourceReferences(sys *types.SystemContext, registryName string, collection filterCollection) []repoDescriptor {
|
||||||
|
var repoDescList []repoDescriptor
|
||||||
|
for repoName, filter := range collection {
|
||||||
|
logger := logrus.WithFields(logrus.Fields{
|
||||||
|
"repo": repoName,
|
||||||
|
"registry": registryName,
|
||||||
|
})
|
||||||
|
|
||||||
|
repoRef, err := parseRepositoryReference(fmt.Sprintf("%s/%s", registryName, repoName))
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error parsing repository name, skipping")
|
||||||
|
logrus.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Processing repo")
|
||||||
|
|
||||||
|
var sourceReferences []types.ImageReference
|
||||||
|
|
||||||
|
logger.Info("Querying registry for image tags")
|
||||||
|
sourceReferences, err = imagesToCopyFromRepo(sys, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error processing repo, skipping")
|
||||||
|
logrus.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var filteredSourceReferences []types.ImageReference
|
||||||
|
for _, ref := range sourceReferences {
|
||||||
|
if filter(logger, ref) {
|
||||||
|
filteredSourceReferences = append(filteredSourceReferences, ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filteredSourceReferences) == 0 {
|
||||||
|
logger.Warnf("No refs to sync found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
repoDescList = append(repoDescList, repoDescriptor{
|
||||||
|
ImageRefs: filteredSourceReferences,
|
||||||
|
Context: sys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return repoDescList
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagRegexFilterCollection converts a map of (repository name, tag regex) pairs
|
||||||
|
// into a filterCollection, which is a map of (repository name, filter function)
|
||||||
|
// pairs.
|
||||||
|
func tagRegexFilterCollection(collection map[string]string) (filterCollection, error) {
|
||||||
|
filters := filterCollection{}
|
||||||
|
|
||||||
|
for repoName, tagRegex := range collection {
|
||||||
|
pattern, err := regexp.Compile(tagRegex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := func(logger *logrus.Entry, sourceReference types.ImageReference) bool {
|
||||||
|
tagged, isTagged := sourceReference.DockerReference().(reference.Tagged)
|
||||||
|
if !isTagged {
|
||||||
|
logger.Errorf("Internal error, reference %s does not have a tag, skipping", sourceReference.DockerReference())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return pattern.MatchString(tagged.Tag())
|
||||||
|
}
|
||||||
|
filters[repoName] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// semverFilterCollection converts a map of (repository name, array of semver constraints) pairs
|
||||||
|
// into a filterCollection, which is a map of (repository name, filter function)
|
||||||
|
// pairs.
|
||||||
|
func semverFilterCollection(collection map[string]string) (filterCollection, error) {
|
||||||
|
filters := filterCollection{}
|
||||||
|
|
||||||
|
for repoName, constraintString := range collection {
|
||||||
|
constraint, err := semver.NewConstraint(constraintString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := func(logger *logrus.Entry, sourceReference types.ImageReference) bool {
|
||||||
|
tagged, isTagged := sourceReference.DockerReference().(reference.Tagged)
|
||||||
|
if !isTagged {
|
||||||
|
logger.Errorf("Internal error, reference %s does not have a tag, skipping", sourceReference.DockerReference())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tagVersion, err := semver.NewVersion(tagged.Tag())
|
||||||
|
if err != nil {
|
||||||
|
logger.Tracef("Tag %q cannot be parsed as semver, skipping", tagged.Tag())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return constraint.Check(tagVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
filters[repoName] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters, nil
|
||||||
|
}
|
||||||
|
|
||||||
// imagesToCopy retrieves all the images to copy from a specified sync source
|
// imagesToCopy retrieves all the images to copy from a specified sync source
|
||||||
// and transport.
|
// and transport.
|
||||||
// It returns a slice of repository descriptors, where each descriptor is a
|
// It returns a slice of repository descriptors, where each descriptor is a
|
||||||
@@ -489,13 +582,6 @@ func imagesToCopy(source string, transport string, sourceCtx *types.SystemContex
|
|||||||
return descriptors, err
|
return descriptors, err
|
||||||
}
|
}
|
||||||
for registryName, registryConfig := range cfg {
|
for registryName, registryConfig := range cfg {
|
||||||
if len(registryConfig.Images) == 0 && len(registryConfig.ImagesByTagRegex) == 0 {
|
|
||||||
logrus.WithFields(logrus.Fields{
|
|
||||||
"registry": registryName,
|
|
||||||
}).Warn("No images specified for registry")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
descs, err := imagesToCopyFromRegistry(registryName, registryConfig, *sourceCtx)
|
descs, err := imagesToCopyFromRegistry(registryName, registryConfig, *sourceCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return descriptors, fmt.Errorf("Failed to retrieve list of images from registry %q: %w", registryName, err)
|
return descriptors, fmt.Errorf("Failed to retrieve list of images from registry %q: %w", registryName, err)
|
||||||
|
@@ -219,6 +219,8 @@ registry.example.com:
|
|||||||
- "sha256:0000000000000000000000000000000011111111111111111111111111111111"
|
- "sha256:0000000000000000000000000000000011111111111111111111111111111111"
|
||||||
images-by-tag-regex:
|
images-by-tag-regex:
|
||||||
nginx: ^1\.13\.[12]-alpine-perl$
|
nginx: ^1\.13\.[12]-alpine-perl$
|
||||||
|
images-by-semver:
|
||||||
|
alpine: ">= 3.12.0"
|
||||||
credentials:
|
credentials:
|
||||||
username: john
|
username: john
|
||||||
password: this is a secret
|
password: this is a secret
|
||||||
@@ -239,6 +241,14 @@ This will copy the following images:
|
|||||||
- Repository `registry.example.com/redis`: images tagged "1.0" and "2.0" along with image with digest "sha256:0000000000000000000000000000000011111111111111111111111111111111".
|
- Repository `registry.example.com/redis`: images tagged "1.0" and "2.0" along with image with digest "sha256:0000000000000000000000000000000011111111111111111111111111111111".
|
||||||
- Repository `registry.example.com/nginx`: images tagged "1.13.1-alpine-perl" and "1.13.2-alpine-perl".
|
- Repository `registry.example.com/nginx`: images tagged "1.13.1-alpine-perl" and "1.13.2-alpine-perl".
|
||||||
- Repository `quay.io/coreos/etcd`: images tagged "latest".
|
- Repository `quay.io/coreos/etcd`: images tagged "latest".
|
||||||
|
- Repository `registry.example.com/alpine`: all images with tags match the semantic version constraint ">= 3.12.0" ("3.12.0, "3.12.1", ... ,"4.0.0", ...)
|
||||||
|
|
||||||
|
The full list of possible semantic version comparisons can be found in the
|
||||||
|
upstream library's documentation:
|
||||||
|
https://github.com/Masterminds/semver/tree/v3.2.0#basic-comparisons.
|
||||||
|
|
||||||
|
Version ordering and precedence is understood as defined here:
|
||||||
|
https://semver.org/#spec-item-11.
|
||||||
|
|
||||||
For the registry `registry.example.com`, the "john"/"this is a secret" credentials are used, with server TLS certificates located at `/home/john/certs`.
|
For the registry `registry.example.com`, the "john"/"this is a secret" credentials are used, with server TLS certificates located at `/home/john/certs`.
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@@ -24,6 +24,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.12.0-rc.1 // indirect
|
github.com/Microsoft/hcsshim v0.12.0-rc.1 // indirect
|
||||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||||
|
2
go.sum
2
go.sum
@@ -6,6 +6,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/Microsoft/hcsshim v0.12.0-rc.1 h1:Hy+xzYujv7urO5wrgcG58SPMOXNLrj4WCJbySs2XX/A=
|
github.com/Microsoft/hcsshim v0.12.0-rc.1 h1:Hy+xzYujv7urO5wrgcG58SPMOXNLrj4WCJbySs2XX/A=
|
||||||
|
1
vendor/github.com/Masterminds/semver/v3/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Masterminds/semver/v3/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_fuzz/
|
27
vendor/github.com/Masterminds/semver/v3/.golangci.yml
generated
vendored
Normal file
27
vendor/github.com/Masterminds/semver/v3/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
run:
|
||||||
|
deadline: 2m
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- misspell
|
||||||
|
- govet
|
||||||
|
- staticcheck
|
||||||
|
- errcheck
|
||||||
|
- unparam
|
||||||
|
- ineffassign
|
||||||
|
- nakedret
|
||||||
|
- gocyclo
|
||||||
|
- dupl
|
||||||
|
- goimports
|
||||||
|
- revive
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- typecheck
|
||||||
|
- unused
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
gofmt:
|
||||||
|
simplify: true
|
||||||
|
dupl:
|
||||||
|
threshold: 600
|
214
vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
generated
vendored
Normal file
214
vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 3.2.0 (2022-11-28)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #190: Added text marshaling and unmarshaling
|
||||||
|
- #167: Added JSON marshalling for constraints (thanks @SimonTheLeg)
|
||||||
|
- #173: Implement encoding.TextMarshaler and encoding.TextUnmarshaler on Version (thanks @MarkRosemaker)
|
||||||
|
- #179: Added New() version constructor (thanks @kazhuravlev)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #182/#183: Updated CI testing setup
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #186: Fixing issue where validation of constraint section gave false positives
|
||||||
|
- #176: Fix constraints check with *-0 (thanks @mtt0)
|
||||||
|
- #181: Fixed Caret operator (^) gives unexpected results when the minor version in constraint is 0 (thanks @arshchimni)
|
||||||
|
- #161: Fixed godoc (thanks @afirth)
|
||||||
|
|
||||||
|
## 3.1.1 (2020-11-23)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #158: Fixed issue with generated regex operation order that could cause problem
|
||||||
|
|
||||||
|
## 3.1.0 (2020-04-15)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #131: Add support for serializing/deserializing SQL (thanks @ryancurrah)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #148: More accurate validation messages on constraints
|
||||||
|
|
||||||
|
## 3.0.3 (2019-12-13)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #141: Fixed issue with <= comparison
|
||||||
|
|
||||||
|
## 3.0.2 (2019-11-14)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #134: Fixed broken constraint checking with ^0.0 (thanks @krmichelos)
|
||||||
|
|
||||||
|
## 3.0.1 (2019-09-13)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #125: Fixes issue with module path for v3
|
||||||
|
|
||||||
|
## 3.0.0 (2019-09-12)
|
||||||
|
|
||||||
|
This is a major release of the semver package which includes API changes. The Go
|
||||||
|
API is compatible with ^1. The Go API was not changed because many people are using
|
||||||
|
`go get` without Go modules for their applications and API breaking changes cause
|
||||||
|
errors which we have or would need to support.
|
||||||
|
|
||||||
|
The changes in this release are the handling based on the data passed into the
|
||||||
|
functions. These are described in the added and changed sections below.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- StrictNewVersion function. This is similar to NewVersion but will return an
|
||||||
|
error if the version passed in is not a strict semantic version. For example,
|
||||||
|
1.2.3 would pass but v1.2.3 or 1.2 would fail because they are not strictly
|
||||||
|
speaking semantic versions. This function is faster, performs fewer operations,
|
||||||
|
and uses fewer allocations than NewVersion.
|
||||||
|
- Fuzzing has been performed on NewVersion, StrictNewVersion, and NewConstraint.
|
||||||
|
The Makefile contains the operations used. For more information on you can start
|
||||||
|
on Wikipedia at https://en.wikipedia.org/wiki/Fuzzing
|
||||||
|
- Now using Go modules
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- NewVersion has proper prerelease and metadata validation with error messages
|
||||||
|
to signal an issue with either of them
|
||||||
|
- ^ now operates using a similar set of rules to npm/js and Rust/Cargo. If the
|
||||||
|
version is >=1 the ^ ranges works the same as v1. For major versions of 0 the
|
||||||
|
rules have changed. The minor version is treated as the stable version unless
|
||||||
|
a patch is specified and then it is equivalent to =. One difference from npm/js
|
||||||
|
is that prereleases there are only to a specific version (e.g. 1.2.3).
|
||||||
|
Prereleases here look over multiple versions and follow semantic version
|
||||||
|
ordering rules. This pattern now follows along with the expected and requested
|
||||||
|
handling of this packaged by numerous users.
|
||||||
|
|
||||||
|
## 1.5.0 (2019-09-11)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil)
|
||||||
|
- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil)
|
||||||
|
- #72: Adding docs comment pointing to vert for a cli
|
||||||
|
- #71: Update the docs on pre-release comparator handling
|
||||||
|
- #89: Test with new go versions (thanks @thedevsaddam)
|
||||||
|
- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #78: Fix unchecked error in example code (thanks @ravron)
|
||||||
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
|
- #97: Fixed copyright file for proper display on GitHub
|
||||||
|
- #107: Fix handling prerelease when sorting alphanum and num
|
||||||
|
- #109: Fixed where Validate sometimes returns wrong message on error
|
||||||
|
|
||||||
|
## 1.4.2 (2018-04-10)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #72: Updated the docs to point to vert for a console appliaction
|
||||||
|
- #71: Update the docs on pre-release comparator handling
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
|
|
||||||
|
## 1.4.1 (2018-04-02)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
|
||||||
|
|
||||||
|
## 1.4.0 (2017-10-04)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
|
||||||
|
|
||||||
|
## 1.3.1 (2017-07-10)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed #57: number comparisons in prerelease sometimes inaccurate
|
||||||
|
|
||||||
|
## 1.3.0 (2017-05-02)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #45: Added json (un)marshaling support (thanks @mh-cbon)
|
||||||
|
- Stability marker. See https://masterminds.github.io/stability/
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #55: The godoc icon moved from png to svg
|
||||||
|
|
||||||
|
## 1.2.3 (2017-04-03)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
|
||||||
|
|
||||||
|
## Release 1.2.2 (2016-12-13)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #34: Fixed issue where hyphen range was not working with pre-release parsing.
|
||||||
|
|
||||||
|
## Release 1.2.1 (2016-11-28)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
|
||||||
|
properly.
|
||||||
|
|
||||||
|
## Release 1.2.0 (2016-11-04)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- #20: Added MustParse function for versions (thanks @adamreese)
|
||||||
|
- #15: Added increment methods on versions (thanks @mh-cbon)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
|
||||||
|
might not satisfy the intended compatibility. The change here ignores pre-releases
|
||||||
|
on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
|
||||||
|
constraint. For example, `^1.2.3` will ignore pre-releases while
|
||||||
|
`^1.2.3-alpha` will include them.
|
||||||
|
|
||||||
|
## Release 1.1.1 (2016-06-30)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Issue #9: Speed up version comparison performance (thanks @sdboyer)
|
||||||
|
- Issue #8: Added benchmarks (thanks @sdboyer)
|
||||||
|
- Updated Go Report Card URL to new location
|
||||||
|
- Updated Readme to add code snippet formatting (thanks @mh-cbon)
|
||||||
|
- Updating tagging to v[SemVer] structure for compatibility with other tools.
|
||||||
|
|
||||||
|
## Release 1.1.0 (2016-03-11)
|
||||||
|
|
||||||
|
- Issue #2: Implemented validation to provide reasons a versions failed a
|
||||||
|
constraint.
|
||||||
|
|
||||||
|
## Release 1.0.1 (2015-12-31)
|
||||||
|
|
||||||
|
- Fixed #1: * constraint failing on valid versions.
|
||||||
|
|
||||||
|
## Release 1.0.0 (2015-10-20)
|
||||||
|
|
||||||
|
- Initial release
|
19
vendor/github.com/Masterminds/semver/v3/LICENSE.txt
generated
vendored
Normal file
19
vendor/github.com/Masterminds/semver/v3/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (C) 2014-2019, Matt Butcher and Matt Farina
|
||||||
|
|
||||||
|
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.
|
30
vendor/github.com/Masterminds/semver/v3/Makefile
generated
vendored
Normal file
30
vendor/github.com/Masterminds/semver/v3/Makefile
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
GOPATH=$(shell go env GOPATH)
|
||||||
|
GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: $(GOLANGCI_LINT)
|
||||||
|
@echo "==> Linting codebase"
|
||||||
|
@$(GOLANGCI_LINT) run
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@echo "==> Running tests"
|
||||||
|
GO111MODULE=on go test -v
|
||||||
|
|
||||||
|
.PHONY: test-cover
|
||||||
|
test-cover:
|
||||||
|
@echo "==> Running Tests with coverage"
|
||||||
|
GO111MODULE=on go test -cover .
|
||||||
|
|
||||||
|
.PHONY: fuzz
|
||||||
|
fuzz:
|
||||||
|
@echo "==> Running Fuzz Tests"
|
||||||
|
go test -fuzz=FuzzNewVersion -fuzztime=15s .
|
||||||
|
go test -fuzz=FuzzStrictNewVersion -fuzztime=15s .
|
||||||
|
go test -fuzz=FuzzNewConstraint -fuzztime=15s .
|
||||||
|
|
||||||
|
$(GOLANGCI_LINT):
|
||||||
|
# Install golangci-lint. The configuration for it is in the .golangci.yml
|
||||||
|
# file in the root of the repository
|
||||||
|
echo ${GOPATH}
|
||||||
|
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1
|
258
vendor/github.com/Masterminds/semver/v3/README.md
generated
vendored
Normal file
258
vendor/github.com/Masterminds/semver/v3/README.md
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
# SemVer
|
||||||
|
|
||||||
|
The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
|
||||||
|
|
||||||
|
* Parse semantic versions
|
||||||
|
* Sort semantic versions
|
||||||
|
* Check if a semantic version fits within a set of constraints
|
||||||
|
* Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
[](https://masterminds.github.io/stability/active.html)
|
||||||
|
[](https://github.com/Masterminds/semver/actions)
|
||||||
|
[](https://pkg.go.dev/github.com/Masterminds/semver/v3)
|
||||||
|
[](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
|
||||||
|
|
||||||
|
Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version.
|
||||||
|
|
||||||
|
There are three major versions fo the `semver` package.
|
||||||
|
|
||||||
|
* 3.x.x is the stable and active version. This version is focused on constraint
|
||||||
|
compatibility for range handling in other tools from other languages. It has
|
||||||
|
a similar API to the v1 releases. The development of this version is on the master
|
||||||
|
branch. The documentation for this version is below.
|
||||||
|
* 2.x was developed primarily for [dep](https://github.com/golang/dep). There are
|
||||||
|
no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer).
|
||||||
|
There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x).
|
||||||
|
* 1.x.x is the original release. It is no longer maintained. You should use the
|
||||||
|
v3 release instead. You can read the documentation for the 1.x.x release
|
||||||
|
[here](https://github.com/Masterminds/semver/blob/release-1/README.md).
|
||||||
|
|
||||||
|
## Parsing Semantic Versions
|
||||||
|
|
||||||
|
There are two functions that can parse semantic versions. The `StrictNewVersion`
|
||||||
|
function only parses valid version 2 semantic versions as outlined in the
|
||||||
|
specification. The `NewVersion` function attempts to coerce a version into a
|
||||||
|
semantic version and parse it. For example, if there is a leading v or a version
|
||||||
|
listed without all 3 parts (e.g. `v1.2`) it will attempt to coerce it into a valid
|
||||||
|
semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
|
||||||
|
that can be sorted, compared, and used in constraints.
|
||||||
|
|
||||||
|
When parsing a version an error is returned if there is an issue parsing the
|
||||||
|
version. For example,
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||||
|
|
||||||
|
The version object has methods to get the parts of the version, compare it to
|
||||||
|
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
|
||||||
|
into a valid form.
|
||||||
|
|
||||||
|
## Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the `sort` package from the standard library.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checking Version Constraints
|
||||||
|
|
||||||
|
There are two methods for comparing versions. One uses comparison methods on
|
||||||
|
`Version` instances and the other uses `Constraints`. There are some important
|
||||||
|
differences to notes between these two methods of comparison.
|
||||||
|
|
||||||
|
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
||||||
|
and others it will follow the specification and always include prereleases
|
||||||
|
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
|
||||||
|
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
|
||||||
|
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
||||||
|
ranges does not include one. If you want to have it include pre-releases a
|
||||||
|
simple solution is to include `-0` in your range.
|
||||||
|
3. Constraint ranges can have some complex rules including the shorthand use of
|
||||||
|
~ and ^. For more details on those see the options below.
|
||||||
|
|
||||||
|
There are differences between the two methods or checking versions because the
|
||||||
|
comparison methods on `Version` follow the specification while comparison ranges
|
||||||
|
are not part of the specification. Different packages and tools have taken it
|
||||||
|
upon themselves to come up with range rules. This has resulted in differences.
|
||||||
|
For example, npm/js and Cargo/Rust follow similar patterns while PHP has a
|
||||||
|
different pattern for ^. The comparison features in this package follow the
|
||||||
|
npm/js and Cargo/Rust lead because applications using it have followed similar
|
||||||
|
patters with their versions.
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parsable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parsable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of space or comma separated AND comparisons. These are then separated by || (OR)
|
||||||
|
comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3.
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
* `=`: equal (aliased to no operator)
|
||||||
|
* `!=`: not equal
|
||||||
|
* `>`: greater than
|
||||||
|
* `<`: less than
|
||||||
|
* `>=`: greater than or equal to
|
||||||
|
* `<=`: less than or equal to
|
||||||
|
|
||||||
|
### Working With Prerelease Versions
|
||||||
|
|
||||||
|
Pre-releases, for those not familiar with them, are used for software releases
|
||||||
|
prior to stable or generally available releases. Examples of prereleases include
|
||||||
|
development, alpha, beta, and release candidate releases. A prerelease may be
|
||||||
|
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
|
||||||
|
example `1.2.3-beta.1 < 1.2.3`.
|
||||||
|
|
||||||
|
According to the Semantic Version specification prereleases may not be
|
||||||
|
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.
|
||||||
|
|
||||||
|
SemVer comparisons using constraints without a prerelease comparator will skip
|
||||||
|
prerelease versions. For example, `>=1.2.3` will skip prereleases when looking
|
||||||
|
at a list of releases while `>=1.2.3-0` will evaluate and find prereleases.
|
||||||
|
|
||||||
|
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
|
||||||
|
`.` separators), per the spec. Sorting happens in ASCII sort order, again per the
|
||||||
|
spec. The lowest character is a `0` in ASCII sort order
|
||||||
|
(see an [ASCII Table](http://www.asciitable.com/))
|
||||||
|
|
||||||
|
Understanding ASCII sort ordering is important because A-Z comes before a-z. That
|
||||||
|
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
|
||||||
|
the spec specifies.
|
||||||
|
|
||||||
|
### Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
* `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`
|
||||||
|
|
||||||
|
### Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the patch level comparison (see tilde below). For example,
|
||||||
|
|
||||||
|
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
* `<= 2.x` is equivalent to `< 3`
|
||||||
|
* `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
### Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||||
|
* `~1` is equivalent to `>= 1, < 2`
|
||||||
|
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||||
|
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `~1.x` is equivalent to `>= 1, < 2`
|
||||||
|
|
||||||
|
### Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes once a stable
|
||||||
|
(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
|
||||||
|
as the API stability level. This is useful when comparisons of API versions as a
|
||||||
|
major change is API breaking. For example,
|
||||||
|
|
||||||
|
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
* `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
|
||||||
|
* `^0.2` is equivalent to `>=0.2.0 <0.3.0`
|
||||||
|
* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
|
||||||
|
* `^0.0` is equivalent to `>=0.0.0 <0.1.0`
|
||||||
|
* `^0` is equivalent to `>=0.0.0 <1.0.0`
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
In addition to testing a version against a constraint, a version can be validated
|
||||||
|
against a constraint. When validation fails a slice of errors containing why a
|
||||||
|
version didn't meet the constraint is returned. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a version against a constraint.
|
||||||
|
a, msgs := c.Validate(v)
|
||||||
|
// a is false
|
||||||
|
for _, m := range msgs {
|
||||||
|
fmt.Println(m)
|
||||||
|
|
||||||
|
// Loops over the errors which would read
|
||||||
|
// "1.3 is greater than 1.2.3"
|
||||||
|
// "1.3 is less than 1.4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
|
||||||
|
or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Security is an important consideration for this project. The project currently
|
||||||
|
uses the following tools to help discover security issues:
|
||||||
|
|
||||||
|
* [CodeQL](https://github.com/Masterminds/semver)
|
||||||
|
* [gosec](https://github.com/securego/gosec)
|
||||||
|
* Daily Fuzz testing
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability you can privately disclose
|
||||||
|
it through the [GitHub security page](https://github.com/Masterminds/semver/security).
|
19
vendor/github.com/Masterminds/semver/v3/SECURITY.md
generated
vendored
Normal file
19
vendor/github.com/Masterminds/semver/v3/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
The following versions of semver are currently supported:
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 3.x | :white_check_mark: |
|
||||||
|
| 2.x | :x: |
|
||||||
|
| 1.x | :x: |
|
||||||
|
|
||||||
|
Fixes are only released for the latest minor version in the form of a patch release.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
You can privately disclose a vulnerability through GitHubs
|
||||||
|
[private vulnerability reporting](https://github.com/Masterminds/semver/security/advisories)
|
||||||
|
mechanism.
|
24
vendor/github.com/Masterminds/semver/v3/collection.go
generated
vendored
Normal file
24
vendor/github.com/Masterminds/semver/v3/collection.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
// Collection is a collection of Version instances and implements the sort
|
||||||
|
// interface. See the sort package for more details.
|
||||||
|
// https://golang.org/pkg/sort/
|
||||||
|
type Collection []*Version
|
||||||
|
|
||||||
|
// Len returns the length of a collection. The number of Version instances
|
||||||
|
// on the slice.
|
||||||
|
func (c Collection) Len() int {
|
||||||
|
return len(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less is needed for the sort interface to compare two Version objects on the
|
||||||
|
// slice. If checks if one is less than the other.
|
||||||
|
func (c Collection) Less(i, j int) bool {
|
||||||
|
return c[i].LessThan(c[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap is needed for the sort interface to replace the Version objects
|
||||||
|
// at two different positions in the slice.
|
||||||
|
func (c Collection) Swap(i, j int) {
|
||||||
|
c[i], c[j] = c[j], c[i]
|
||||||
|
}
|
594
vendor/github.com/Masterminds/semver/v3/constraints.go
generated
vendored
Normal file
594
vendor/github.com/Masterminds/semver/v3/constraints.go
generated
vendored
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constraints is one or more constraint that a semantic version can be
|
||||||
|
// checked against.
|
||||||
|
type Constraints struct {
|
||||||
|
constraints [][]*constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConstraint returns a Constraints instance that a Version instance can
|
||||||
|
// be checked against. If there is a parse error it will be returned.
|
||||||
|
func NewConstraint(c string) (*Constraints, error) {
|
||||||
|
|
||||||
|
// Rewrite - ranges into a comparison operation.
|
||||||
|
c = rewriteRange(c)
|
||||||
|
|
||||||
|
ors := strings.Split(c, "||")
|
||||||
|
or := make([][]*constraint, len(ors))
|
||||||
|
for k, v := range ors {
|
||||||
|
|
||||||
|
// TODO: Find a way to validate and fetch all the constraints in a simpler form
|
||||||
|
|
||||||
|
// Validate the segment
|
||||||
|
if !validConstraintRegex.MatchString(v) {
|
||||||
|
return nil, fmt.Errorf("improper constraint: %s", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := findConstraintRegex.FindAllString(v, -1)
|
||||||
|
if cs == nil {
|
||||||
|
cs = append(cs, v)
|
||||||
|
}
|
||||||
|
result := make([]*constraint, len(cs))
|
||||||
|
for i, s := range cs {
|
||||||
|
pc, err := parseConstraint(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = pc
|
||||||
|
}
|
||||||
|
or[k] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &Constraints{constraints: or}
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tests if a version satisfies the constraints.
|
||||||
|
func (cs Constraints) Check(v *Version) bool {
|
||||||
|
// TODO(mattfarina): For v4 of this library consolidate the Check and Validate
|
||||||
|
// functions as the underlying functions make that possible now.
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
if check, _ := c.check(v); !check {
|
||||||
|
joy = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks if a version satisfies a constraint. If not a slice of
|
||||||
|
// reasons for the failure are returned in addition to a bool.
|
||||||
|
func (cs Constraints) Validate(v *Version) (bool, []error) {
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
var e []error
|
||||||
|
|
||||||
|
// Capture the prerelease message only once. When it happens the first time
|
||||||
|
// this var is marked
|
||||||
|
var prerelesase bool
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
// Before running the check handle the case there the version is
|
||||||
|
// a prerelease and the check is not searching for prereleases.
|
||||||
|
if c.con.pre == "" && v.pre != "" {
|
||||||
|
if !prerelesase {
|
||||||
|
em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
|
e = append(e, em)
|
||||||
|
prerelesase = true
|
||||||
|
}
|
||||||
|
joy = false
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if _, err := c.check(v); err != nil {
|
||||||
|
e = append(e, err)
|
||||||
|
joy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true, []error{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs Constraints) String() string {
|
||||||
|
buf := make([]string, len(cs.constraints))
|
||||||
|
var tmp bytes.Buffer
|
||||||
|
|
||||||
|
for k, v := range cs.constraints {
|
||||||
|
tmp.Reset()
|
||||||
|
vlen := len(v)
|
||||||
|
for kk, c := range v {
|
||||||
|
tmp.WriteString(c.string())
|
||||||
|
|
||||||
|
// Space separate the AND conditions
|
||||||
|
if vlen > 1 && kk < vlen-1 {
|
||||||
|
tmp.WriteString(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[k] = tmp.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(buf, " || ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
func (cs *Constraints) UnmarshalText(text []byte) error {
|
||||||
|
temp, err := NewConstraint(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*cs = *temp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
func (cs Constraints) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(cs.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintOps map[string]cfunc
|
||||||
|
var constraintRegex *regexp.Regexp
|
||||||
|
var constraintRangeRegex *regexp.Regexp
|
||||||
|
|
||||||
|
// Used to find individual constraints within a multi-constraint string
|
||||||
|
var findConstraintRegex *regexp.Regexp
|
||||||
|
|
||||||
|
// Used to validate an segment of ANDs is valid
|
||||||
|
var validConstraintRegex *regexp.Regexp
|
||||||
|
|
||||||
|
const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
|
||||||
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
constraintOps = map[string]cfunc{
|
||||||
|
"": constraintTildeOrEqual,
|
||||||
|
"=": constraintTildeOrEqual,
|
||||||
|
"!=": constraintNotEqual,
|
||||||
|
">": constraintGreaterThan,
|
||||||
|
"<": constraintLessThan,
|
||||||
|
">=": constraintGreaterThanEqual,
|
||||||
|
"=>": constraintGreaterThanEqual,
|
||||||
|
"<=": constraintLessThanEqual,
|
||||||
|
"=<": constraintLessThanEqual,
|
||||||
|
"~": constraintTilde,
|
||||||
|
"~>": constraintTilde,
|
||||||
|
"^": constraintCaret,
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\^`
|
||||||
|
|
||||||
|
constraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`^\s*(%s)\s*(%s)\s*$`,
|
||||||
|
ops,
|
||||||
|
cvRegex))
|
||||||
|
|
||||||
|
constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`\s*(%s)\s+-\s+(%s)\s*`,
|
||||||
|
cvRegex, cvRegex))
|
||||||
|
|
||||||
|
findConstraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`(%s)\s*(%s)`,
|
||||||
|
ops,
|
||||||
|
cvRegex))
|
||||||
|
|
||||||
|
// The first time a constraint shows up will look slightly different from
|
||||||
|
// future times it shows up due to a leading space or comma in a given
|
||||||
|
// string.
|
||||||
|
validConstraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`^(\s*(%s)\s*(%s)\s*)((?:\s+|,\s*)(%s)\s*(%s)\s*)*$`,
|
||||||
|
ops,
|
||||||
|
cvRegex,
|
||||||
|
ops,
|
||||||
|
cvRegex))
|
||||||
|
}
|
||||||
|
|
||||||
|
// An individual constraint
|
||||||
|
type constraint struct {
|
||||||
|
// The version used in the constraint check. For example, if a constraint
|
||||||
|
// is '<= 2.0.0' the con a version instance representing 2.0.0.
|
||||||
|
con *Version
|
||||||
|
|
||||||
|
// The original parsed version (e.g., 4.x from != 4.x)
|
||||||
|
orig string
|
||||||
|
|
||||||
|
// The original operator for the constraint
|
||||||
|
origfunc string
|
||||||
|
|
||||||
|
// When an x is used as part of the version (e.g., 1.x)
|
||||||
|
minorDirty bool
|
||||||
|
dirty bool
|
||||||
|
patchDirty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a version meets the constraint
|
||||||
|
func (c *constraint) check(v *Version) (bool, error) {
|
||||||
|
return constraintOps[c.origfunc](v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String prints an individual constraint into a string
|
||||||
|
func (c *constraint) string() string {
|
||||||
|
return c.origfunc + c.orig
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfunc func(v *Version, c *constraint) (bool, error)
|
||||||
|
|
||||||
|
func parseConstraint(c string) (*constraint, error) {
|
||||||
|
if len(c) > 0 {
|
||||||
|
m := constraintRegex.FindStringSubmatch(c)
|
||||||
|
if m == nil {
|
||||||
|
return nil, fmt.Errorf("improper constraint: %s", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := &constraint{
|
||||||
|
orig: m[2],
|
||||||
|
origfunc: m[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
ver := m[2]
|
||||||
|
minorDirty := false
|
||||||
|
patchDirty := false
|
||||||
|
dirty := false
|
||||||
|
if isX(m[3]) || m[3] == "" {
|
||||||
|
ver = fmt.Sprintf("0.0.0%s", m[6])
|
||||||
|
dirty = true
|
||||||
|
} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
|
||||||
|
minorDirty = true
|
||||||
|
dirty = true
|
||||||
|
ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
|
||||||
|
} else if isX(strings.TrimPrefix(m[5], ".")) || m[5] == "" {
|
||||||
|
dirty = true
|
||||||
|
patchDirty = true
|
||||||
|
ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
|
||||||
|
}
|
||||||
|
|
||||||
|
con, err := NewVersion(ver)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
|
// we should never get here.
|
||||||
|
return nil, errors.New("constraint Parser Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.con = con
|
||||||
|
cs.minorDirty = minorDirty
|
||||||
|
cs.patchDirty = patchDirty
|
||||||
|
cs.dirty = dirty
|
||||||
|
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The rest is the special case where an empty string was passed in which
|
||||||
|
// is equivalent to * or >=0.0.0
|
||||||
|
con, err := StrictNewVersion("0.0.0")
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
|
// we should never get here.
|
||||||
|
return nil, errors.New("constraint Parser Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := &constraint{
|
||||||
|
con: con,
|
||||||
|
orig: c,
|
||||||
|
origfunc: "",
|
||||||
|
minorDirty: false,
|
||||||
|
patchDirty: false,
|
||||||
|
dirty: true,
|
||||||
|
}
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constraint functions
|
||||||
|
func constraintNotEqual(v *Version, c *constraint) (bool, error) {
|
||||||
|
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() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if c.con.Minor() != v.Minor() && !c.minorDirty {
|
||||||
|
return true, nil
|
||||||
|
} else if c.minorDirty {
|
||||||
|
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
||||||
|
} else if c.con.Patch() != v.Patch() && !c.patchDirty {
|
||||||
|
return true, nil
|
||||||
|
} else if c.patchDirty {
|
||||||
|
// Need to handle prereleases if present
|
||||||
|
if v.Prerelease() != "" || c.con.Prerelease() != "" {
|
||||||
|
eq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eq := v.Equal(c.con)
|
||||||
|
if eq {
|
||||||
|
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThan(v *Version, c *constraint) (bool, error) {
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
var eq bool
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
eq = v.Compare(c.con) == 1
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return true, nil
|
||||||
|
} else if v.Major() < c.con.Major() {
|
||||||
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
|
} else if c.minorDirty {
|
||||||
|
// This is a range case such as >11. When the version is something like
|
||||||
|
// 11.1.0 is it not > 11. For that we would need 12 or higher
|
||||||
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
|
} else if c.patchDirty {
|
||||||
|
// This is for ranges such as >11.1. A version of 11.1.1 is not greater
|
||||||
|
// which one of 11.2.1 is greater
|
||||||
|
eq = v.Minor() > c.con.Minor()
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have gotten here we are not comparing pre-preleases and can use the
|
||||||
|
// Compare function to accomplish that.
|
||||||
|
eq = v.Compare(c.con) == 1
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThan(v *Version, c *constraint) (bool, error) {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
eq := v.Compare(c.con) < 0
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) {
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
eq := v.Compare(c.con) >= 0
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThanEqual(v *Version, c *constraint) (bool, error) {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
var eq bool
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
eq = v.Compare(c.con) <= 0
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
||||||
|
} else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||||
|
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~*, ~>* --> >= 0.0.0 (any)
|
||||||
|
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
|
||||||
|
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.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.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
||||||
|
func constraintTilde(v *Version, c *constraint) (bool, error) {
|
||||||
|
// 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 v.LessThan(c.con) {
|
||||||
|
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~0.0.0 is a special case where all constraints are accepted. It's
|
||||||
|
// equivalent to >= 0.0.0.
|
||||||
|
if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
|
||||||
|
!c.minorDirty && !c.patchDirty {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() != c.con.Major() {
|
||||||
|
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Minor() != c.con.Minor() && !c.minorDirty {
|
||||||
|
return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
||||||
|
// it's a straight =
|
||||||
|
func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) {
|
||||||
|
// 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.dirty {
|
||||||
|
return constraintTilde(v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
eq := v.Equal(c.con)
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, fmt.Errorf("%s is not equal to %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^* --> (any)
|
||||||
|
// ^1.2.3 --> >=1.2.3 <2.0.0
|
||||||
|
// ^1.2 --> >=1.2.0 <2.0.0
|
||||||
|
// ^1 --> >=1.0.0 <2.0.0
|
||||||
|
// ^0.2.3 --> >=0.2.3 <0.3.0
|
||||||
|
// ^0.2 --> >=0.2.0 <0.3.0
|
||||||
|
// ^0.0.3 --> >=0.0.3 <0.0.4
|
||||||
|
// ^0.0 --> >=0.0.0 <0.1.0
|
||||||
|
// ^0 --> >=0.0.0 <1.0.0
|
||||||
|
func constraintCaret(v *Version, c *constraint) (bool, error) {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This less than handles prereleases
|
||||||
|
if v.LessThan(c.con) {
|
||||||
|
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
var eq bool
|
||||||
|
|
||||||
|
// ^ when the major > 0 is >=x.y.z < x+1
|
||||||
|
if c.con.Major() > 0 || c.minorDirty {
|
||||||
|
|
||||||
|
// ^ has to be within a major range for > 0. Everything less than was
|
||||||
|
// filtered out with the LessThan call above. This filters out those
|
||||||
|
// that greater but not within the same major range.
|
||||||
|
eq = v.Major() == c.con.Major()
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
|
||||||
|
if c.con.Major() == 0 && v.Major() > 0 {
|
||||||
|
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
||||||
|
}
|
||||||
|
// If the con Minor is > 0 it is not dirty
|
||||||
|
if c.con.Minor() > 0 || c.patchDirty {
|
||||||
|
eq = v.Minor() == c.con.Minor()
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig)
|
||||||
|
}
|
||||||
|
// ^ when the minor is 0 and minor > 0 is =0.0.z
|
||||||
|
if c.con.Minor() == 0 && v.Minor() > 0 {
|
||||||
|
return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point the major is 0 and the minor is 0 and not dirty. The patch
|
||||||
|
// is not dirty so we need to check if they are equal. If they are not equal
|
||||||
|
eq = c.con.Patch() == v.Patch()
|
||||||
|
if eq {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isX(x string) bool {
|
||||||
|
switch x {
|
||||||
|
case "x", "*", "X":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewriteRange(i string) string {
|
||||||
|
m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
|
||||||
|
if m == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
o := i
|
||||||
|
for _, v := range m {
|
||||||
|
t := fmt.Sprintf(">= %s, <= %s ", v[1], v[11])
|
||||||
|
o = strings.Replace(o, v[0], t, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
184
vendor/github.com/Masterminds/semver/v3/doc.go
generated
vendored
Normal file
184
vendor/github.com/Masterminds/semver/v3/doc.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
|
||||||
|
|
||||||
|
Specifically it provides the ability to:
|
||||||
|
|
||||||
|
- Parse semantic versions
|
||||||
|
- Sort semantic versions
|
||||||
|
- Check if a semantic version fits within a set of constraints
|
||||||
|
- Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
# Parsing Semantic Versions
|
||||||
|
|
||||||
|
There are two functions that can parse semantic versions. The `StrictNewVersion`
|
||||||
|
function only parses valid version 2 semantic versions as outlined in the
|
||||||
|
specification. The `NewVersion` function attempts to coerce a version into a
|
||||||
|
semantic version and parse it. For example, if there is a leading v or a version
|
||||||
|
listed without all 3 parts (e.g. 1.2) it will attempt to coerce it into a valid
|
||||||
|
semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
|
||||||
|
that can be sorted, compared, and used in constraints.
|
||||||
|
|
||||||
|
When parsing a version an optional error can be returned if there is an issue
|
||||||
|
parsing the version. For example,
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+b345")
|
||||||
|
|
||||||
|
The version object has methods to get the parts of the version, compare it to
|
||||||
|
other versions, convert the version back into a string, and get the original
|
||||||
|
string. For more details please see the documentation
|
||||||
|
at https://godoc.org/github.com/Masterminds/semver.
|
||||||
|
|
||||||
|
# Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the `sort` package from the standard library.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
|
||||||
|
# Checking Version Constraints and Comparing Versions
|
||||||
|
|
||||||
|
There are two methods for comparing versions. One uses comparison methods on
|
||||||
|
`Version` instances and the other is using Constraints. There are some important
|
||||||
|
differences to notes between these two methods of comparison.
|
||||||
|
|
||||||
|
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
||||||
|
and others it will follow the specification and always include prereleases
|
||||||
|
within the comparison. It will provide an answer valid with the comparison
|
||||||
|
spec section at https://semver.org/#spec-item-11
|
||||||
|
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
|
||||||
|
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
||||||
|
ranges does not include on. If you want to have it include pre-releases a
|
||||||
|
simple solution is to include `-0` in your range.
|
||||||
|
3. Constraint ranges can have some complex rules including the shorthard use of
|
||||||
|
~ and ^. For more details on those see the options below.
|
||||||
|
|
||||||
|
There are differences between the two methods or checking versions because the
|
||||||
|
comparison methods on `Version` follow the specification while comparison ranges
|
||||||
|
are not part of the specification. Different packages and tools have taken it
|
||||||
|
upon themselves to come up with range rules. This has resulted in differences.
|
||||||
|
For example, npm/js and Cargo/Rust follow similar patterns which PHP has a
|
||||||
|
different pattern for ^. The comparison features in this package follow the
|
||||||
|
npm/js and Cargo/Rust lead because applications using it have followed similar
|
||||||
|
patters with their versions.
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parsable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parsable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
|
||||||
|
# Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of comma or space separated AND comparisons. These are then separated by || (OR)
|
||||||
|
comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3. This can also be written as
|
||||||
|
`">= 1.2, < 3.0.0 || >= 4.2.3"`
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
- `=`: equal (aliased to no operator)
|
||||||
|
- `!=`: not equal
|
||||||
|
- `>`: greater than
|
||||||
|
- `<`: less than
|
||||||
|
- `>=`: greater than or equal to
|
||||||
|
- `<=`: less than or equal to
|
||||||
|
|
||||||
|
# Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
- `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`
|
||||||
|
|
||||||
|
# Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the tilde operation. For example,
|
||||||
|
|
||||||
|
- `1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
|
||||||
|
- `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
- `<= 2.x` is equivalent to `<= 3`
|
||||||
|
- `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
- `~1.2.3` is equivalent to `>= 1.2.3 < 1.3.0`
|
||||||
|
- `~1` is equivalent to `>= 1, < 2`
|
||||||
|
- `~2.3` is equivalent to `>= 2.3 < 2.4`
|
||||||
|
- `~1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
|
||||||
|
- `~1.x` is equivalent to `>= 1 < 2`
|
||||||
|
|
||||||
|
Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes once a stable
|
||||||
|
(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
|
||||||
|
as the API stability level. This is useful when comparisons of API versions as a
|
||||||
|
major change is API breaking. For example,
|
||||||
|
|
||||||
|
- `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
- `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
- `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
- `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
- `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
|
||||||
|
- `^0.2` is equivalent to `>=0.2.0 <0.3.0`
|
||||||
|
- `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
|
||||||
|
- `^0.0` is equivalent to `>=0.0.0 <0.1.0`
|
||||||
|
- `^0` is equivalent to `>=0.0.0 <1.0.0`
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
|
||||||
|
In addition to testing a version against a constraint, a version can be validated
|
||||||
|
against a constraint. When validation fails a slice of errors containing why a
|
||||||
|
version didn't meet the constraint is returned. For example,
|
||||||
|
|
||||||
|
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a version against a constraint.
|
||||||
|
a, msgs := c.Validate(v)
|
||||||
|
// a is false
|
||||||
|
for _, m := range msgs {
|
||||||
|
fmt.Println(m)
|
||||||
|
|
||||||
|
// Loops over the errors which would read
|
||||||
|
// "1.3 is greater than 1.2.3"
|
||||||
|
// "1.3 is less than 1.4"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package semver
|
639
vendor/github.com/Masterminds/semver/v3/version.go
generated
vendored
Normal file
639
vendor/github.com/Masterminds/semver/v3/version.go
generated
vendored
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The compiled version of the regex created at init() is cached here so it
|
||||||
|
// only needs to be created once.
|
||||||
|
var versionRegex *regexp.Regexp
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidSemVer is returned a version is found to be invalid when
|
||||||
|
// being parsed.
|
||||||
|
ErrInvalidSemVer = errors.New("Invalid Semantic Version")
|
||||||
|
|
||||||
|
// ErrEmptyString is returned when an empty string is passed in for parsing.
|
||||||
|
ErrEmptyString = errors.New("Version string empty")
|
||||||
|
|
||||||
|
// ErrInvalidCharacters is returned when invalid characters are found as
|
||||||
|
// part of a version
|
||||||
|
ErrInvalidCharacters = errors.New("Invalid characters in version")
|
||||||
|
|
||||||
|
// ErrSegmentStartsZero is returned when a version segment starts with 0.
|
||||||
|
// This is invalid in SemVer.
|
||||||
|
ErrSegmentStartsZero = errors.New("Version segment starts with 0")
|
||||||
|
|
||||||
|
// ErrInvalidMetadata is returned when the metadata is an invalid format
|
||||||
|
ErrInvalidMetadata = errors.New("Invalid Metadata string")
|
||||||
|
|
||||||
|
// ErrInvalidPrerelease is returned when the pre-release is an invalid format
|
||||||
|
ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
|
||||||
|
)
|
||||||
|
|
||||||
|
// semVerRegex is the regular expression used to parse a semantic version.
|
||||||
|
const semVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
|
||||||
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
|
// Version represents a single semantic version.
|
||||||
|
type Version struct {
|
||||||
|
major, minor, patch uint64
|
||||||
|
pre string
|
||||||
|
metadata string
|
||||||
|
original string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
versionRegex = regexp.MustCompile("^" + semVerRegex + "$")
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
num string = "0123456789"
|
||||||
|
allowed string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + num
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrictNewVersion parses a given version and returns an instance of Version or
|
||||||
|
// an error if unable to parse the version. Only parses valid semantic versions.
|
||||||
|
// Performs checking that can find errors within the version.
|
||||||
|
// If you want to coerce a version such as 1 or 1.2 and parse it as the 1.x
|
||||||
|
// releases of semver did, use the NewVersion() function.
|
||||||
|
func StrictNewVersion(v string) (*Version, error) {
|
||||||
|
// Parsing here does not use RegEx in order to increase performance and reduce
|
||||||
|
// allocations.
|
||||||
|
|
||||||
|
if len(v) == 0 {
|
||||||
|
return nil, ErrEmptyString
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build
|
||||||
|
parts := strings.SplitN(v, ".", 3)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := &Version{
|
||||||
|
original: v,
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for prerelease or build metadata
|
||||||
|
var extra []string
|
||||||
|
if strings.ContainsAny(parts[2], "-+") {
|
||||||
|
// Start with the build metadata first as it needs to be on the right
|
||||||
|
extra = strings.SplitN(parts[2], "+", 2)
|
||||||
|
if len(extra) > 1 {
|
||||||
|
// build metadata found
|
||||||
|
sv.metadata = extra[1]
|
||||||
|
parts[2] = extra[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
extra = strings.SplitN(parts[2], "-", 2)
|
||||||
|
if len(extra) > 1 {
|
||||||
|
// prerelease found
|
||||||
|
sv.pre = extra[1]
|
||||||
|
parts[2] = extra[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the number segments are valid. This includes only having positive
|
||||||
|
// numbers and no leading 0's.
|
||||||
|
for _, p := range parts {
|
||||||
|
if !containsOnly(p, num) {
|
||||||
|
return nil, ErrInvalidCharacters
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p) > 1 && p[0] == '0' {
|
||||||
|
return nil, ErrSegmentStartsZero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the major, minor, and patch elements onto the returned Version
|
||||||
|
var err error
|
||||||
|
sv.major, err = strconv.ParseUint(parts[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sv.minor, err = strconv.ParseUint(parts[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sv.patch, err = strconv.ParseUint(parts[2], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No prerelease or build metadata found so returning now as a fastpath.
|
||||||
|
if sv.pre == "" && sv.metadata == "" {
|
||||||
|
return sv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.pre != "" {
|
||||||
|
if err = validatePrerelease(sv.pre); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.metadata != "" {
|
||||||
|
if err = validateMetadata(sv.metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
m := versionRegex.FindStringSubmatch(v)
|
||||||
|
if m == nil {
|
||||||
|
return nil, ErrInvalidSemVer
|
||||||
|
}
|
||||||
|
|
||||||
|
sv := &Version{
|
||||||
|
metadata: m[8],
|
||||||
|
pre: m[5],
|
||||||
|
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: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[2] != "" {
|
||||||
|
sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sv.minor = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[3] != "" {
|
||||||
|
sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error parsing version segment: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sv.patch = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform some basic due diligence on the extra parts to ensure they are
|
||||||
|
// valid.
|
||||||
|
|
||||||
|
if sv.pre != "" {
|
||||||
|
if err = validatePrerelease(sv.pre); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.metadata != "" {
|
||||||
|
if err = validateMetadata(sv.metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of Version with each of the parts passed in as
|
||||||
|
// arguments instead of parsing a version string.
|
||||||
|
func New(major, minor, patch uint64, pre, metadata string) *Version {
|
||||||
|
v := Version{
|
||||||
|
major: major,
|
||||||
|
minor: minor,
|
||||||
|
patch: patch,
|
||||||
|
pre: pre,
|
||||||
|
metadata: metadata,
|
||||||
|
original: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
v.original = v.String()
|
||||||
|
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse parses a given version and panics on error.
|
||||||
|
func MustParse(v string) *Version {
|
||||||
|
sv, err := NewVersion(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return sv
|
||||||
|
}
|
||||||
|
|
||||||
|
// String converts a Version object to a string.
|
||||||
|
// Note, if the original version contained a leading v this version will not.
|
||||||
|
// See the Original() method to retrieve the original value. Semantic Versions
|
||||||
|
// don't contain a leading v per the spec. Instead it's optional on
|
||||||
|
// implementation.
|
||||||
|
func (v Version) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
|
||||||
|
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 value passed in to be parsed.
|
||||||
|
func (v *Version) Original() string {
|
||||||
|
return v.original
|
||||||
|
}
|
||||||
|
|
||||||
|
// Major returns the major version.
|
||||||
|
func (v Version) Major() uint64 {
|
||||||
|
return v.major
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor version.
|
||||||
|
func (v Version) Minor() uint64 {
|
||||||
|
return v.minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch returns the patch version.
|
||||||
|
func (v Version) Patch() uint64 {
|
||||||
|
return v.patch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerelease returns the pre-release version.
|
||||||
|
func (v Version) Prerelease() string {
|
||||||
|
return v.pre
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata returns the metadata on the version.
|
||||||
|
func (v Version) Metadata() string {
|
||||||
|
return v.metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
// originalVPrefix returns the original 'v' prefix if any.
|
||||||
|
func (v Version) originalVPrefix() string {
|
||||||
|
// Note, only lowercase v is supported as a prefix by the parser.
|
||||||
|
if v.original != "" && v.original[:1] == "v" {
|
||||||
|
return v.original[:1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncPatch produces the next patch version.
|
||||||
|
// If the current version does not have prerelease/metadata information,
|
||||||
|
// it unsets metadata and prerelease values, increments patch number.
|
||||||
|
// If the current version has any of prerelease or metadata information,
|
||||||
|
// it unsets both values and keeps current patch value
|
||||||
|
func (v Version) IncPatch() Version {
|
||||||
|
vNext := v
|
||||||
|
// according to http://semver.org/#spec-item-9
|
||||||
|
// Pre-release versions have a lower precedence than the associated normal version.
|
||||||
|
// according to http://semver.org/#spec-item-10
|
||||||
|
// Build metadata SHOULD be ignored when determining version precedence.
|
||||||
|
if v.pre != "" {
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
} else {
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = v.patch + 1
|
||||||
|
}
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncMinor produces the next minor version.
|
||||||
|
// Sets patch to 0.
|
||||||
|
// Increments minor number.
|
||||||
|
// Unsets metadata.
|
||||||
|
// Unsets prerelease status.
|
||||||
|
func (v Version) IncMinor() Version {
|
||||||
|
vNext := v
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = 0
|
||||||
|
vNext.minor = v.minor + 1
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncMajor produces the next major version.
|
||||||
|
// Sets patch to 0.
|
||||||
|
// Sets minor to 0.
|
||||||
|
// Increments major number.
|
||||||
|
// Unsets metadata.
|
||||||
|
// Unsets prerelease status.
|
||||||
|
func (v Version) IncMajor() Version {
|
||||||
|
vNext := v
|
||||||
|
vNext.metadata = ""
|
||||||
|
vNext.pre = ""
|
||||||
|
vNext.patch = 0
|
||||||
|
vNext.minor = 0
|
||||||
|
vNext.major = v.major + 1
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrerelease defines the prerelease value.
|
||||||
|
// Value must not include the required 'hyphen' prefix.
|
||||||
|
func (v Version) SetPrerelease(prerelease string) (Version, error) {
|
||||||
|
vNext := v
|
||||||
|
if len(prerelease) > 0 {
|
||||||
|
if err := validatePrerelease(prerelease); err != nil {
|
||||||
|
return vNext, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vNext.pre = prerelease
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMetadata defines metadata value.
|
||||||
|
// Value must not include the required 'plus' prefix.
|
||||||
|
func (v Version) SetMetadata(metadata string) (Version, error) {
|
||||||
|
vNext := v
|
||||||
|
if len(metadata) > 0 {
|
||||||
|
if err := validateMetadata(metadata); err != nil {
|
||||||
|
return vNext, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vNext.metadata = metadata
|
||||||
|
vNext.original = v.originalVPrefix() + "" + vNext.String()
|
||||||
|
return vNext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessThan tests if one version is less than another one.
|
||||||
|
func (v *Version) LessThan(o *Version) bool {
|
||||||
|
return v.Compare(o) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterThan tests if one version is greater than another one.
|
||||||
|
func (v *Version) GreaterThan(o *Version) bool {
|
||||||
|
return v.Compare(o) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal tests if two versions are equal to each other.
|
||||||
|
// Note, versions can be equal with different metadata since metadata
|
||||||
|
// is not considered part of the comparable version.
|
||||||
|
func (v *Version) Equal(o *Version) bool {
|
||||||
|
return v.Compare(o) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare compares this version to another one. It returns -1, 0, or 1 if
|
||||||
|
// the version smaller, equal, or larger than the other version.
|
||||||
|
//
|
||||||
|
// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
|
||||||
|
// lower than the version without a prerelease. Compare always takes into account
|
||||||
|
// prereleases. If you want to work with ranges using typical range syntaxes that
|
||||||
|
// skip prereleases if the range is not looking for them use constraints.
|
||||||
|
func (v *Version) Compare(o *Version) int {
|
||||||
|
// Compare the major, minor, and patch version for differences. If a
|
||||||
|
// difference is found return the comparison.
|
||||||
|
if d := compareSegment(v.Major(), o.Major()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point the major, minor, and patch versions are the same.
|
||||||
|
ps := v.pre
|
||||||
|
po := o.Prerelease()
|
||||||
|
|
||||||
|
if ps == "" && po == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if ps == "" {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if po == "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return comparePrerelease(ps, po)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements JSON.Unmarshaler interface.
|
||||||
|
func (v *Version) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
temp, err := NewVersion(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.major = temp.major
|
||||||
|
v.minor = temp.minor
|
||||||
|
v.patch = temp.patch
|
||||||
|
v.pre = temp.pre
|
||||||
|
v.metadata = temp.metadata
|
||||||
|
v.original = temp.original
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements JSON.Marshaler interface.
|
||||||
|
func (v Version) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
func (v *Version) UnmarshalText(text []byte) error {
|
||||||
|
temp, err := NewVersion(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = *temp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
func (v Version) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(v.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the SQL.Scanner interface.
|
||||||
|
func (v *Version) Scan(value interface{}) error {
|
||||||
|
var s string
|
||||||
|
s, _ = value.(string)
|
||||||
|
temp, err := NewVersion(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.major = temp.major
|
||||||
|
v.minor = temp.minor
|
||||||
|
v.patch = temp.patch
|
||||||
|
v.pre = temp.pre
|
||||||
|
v.metadata = temp.metadata
|
||||||
|
v.original = temp.original
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the Driver.Valuer interface.
|
||||||
|
func (v Version) Value() (driver.Value, error) {
|
||||||
|
return v.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareSegment(v, o uint64) int {
|
||||||
|
if v < o {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if v > o {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrerelease(v, o string) int {
|
||||||
|
// split the prelease versions by their part. The separator, per the spec,
|
||||||
|
// is a .
|
||||||
|
sparts := strings.Split(v, ".")
|
||||||
|
oparts := strings.Split(o, ".")
|
||||||
|
|
||||||
|
// Find the longer length of the parts to know how many loop iterations to
|
||||||
|
// go through.
|
||||||
|
slen := len(sparts)
|
||||||
|
olen := len(oparts)
|
||||||
|
|
||||||
|
l := slen
|
||||||
|
if olen > slen {
|
||||||
|
l = olen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each part of the prereleases to compare the differences.
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
// Since the lentgh of the parts can be different we need to create
|
||||||
|
// a placeholder. This is to avoid out of bounds issues.
|
||||||
|
stemp := ""
|
||||||
|
if i < slen {
|
||||||
|
stemp = sparts[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
otemp := ""
|
||||||
|
if i < olen {
|
||||||
|
otemp = oparts[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
d := comparePrePart(stemp, otemp)
|
||||||
|
if d != 0 {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaching here means two versions are of equal value but have different
|
||||||
|
// metadata (the part following a +). They are not identical in string form
|
||||||
|
// but the version comparison finds them to be equal.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrePart(s, o string) int {
|
||||||
|
// Fastpath if they are equal
|
||||||
|
if s == o {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// When s or o are empty we can use the other in an attempt to determine
|
||||||
|
// the response.
|
||||||
|
if s == "" {
|
||||||
|
if o != "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if o == "" {
|
||||||
|
if s != "" {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// When comparing strings "99" is greater than "103". To handle
|
||||||
|
// cases like this we need to detect numbers and compare them. According
|
||||||
|
// to the semver spec, numbers are always positive. If there is a - at the
|
||||||
|
// start like -99 this is to be evaluated as an alphanum. numbers always
|
||||||
|
// have precedence over alphanum. Parsing as Uints because negative numbers
|
||||||
|
// are ignored.
|
||||||
|
|
||||||
|
oi, n1 := strconv.ParseUint(o, 10, 64)
|
||||||
|
si, n2 := strconv.ParseUint(s, 10, 64)
|
||||||
|
|
||||||
|
// The case where both are strings compare the strings
|
||||||
|
if n1 != nil && n2 != nil {
|
||||||
|
if s > o {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
} else if n1 != nil {
|
||||||
|
// o is a string and s is a number
|
||||||
|
return -1
|
||||||
|
} else if n2 != nil {
|
||||||
|
// s is a string and o is a number
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// Both are numbers
|
||||||
|
if si > oi {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like strings.ContainsAny but does an only instead of any.
|
||||||
|
func containsOnly(s string, comp string) bool {
|
||||||
|
return strings.IndexFunc(s, func(r rune) bool {
|
||||||
|
return !strings.ContainsRune(comp, r)
|
||||||
|
}) == -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the spec, "Identifiers MUST comprise only
|
||||||
|
// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
|
||||||
|
// Numeric identifiers MUST NOT include leading zeroes.". These segments can
|
||||||
|
// be dot separated.
|
||||||
|
func validatePrerelease(p string) error {
|
||||||
|
eparts := strings.Split(p, ".")
|
||||||
|
for _, p := range eparts {
|
||||||
|
if containsOnly(p, num) {
|
||||||
|
if len(p) > 1 && p[0] == '0' {
|
||||||
|
return ErrSegmentStartsZero
|
||||||
|
}
|
||||||
|
} else if !containsOnly(p, allowed) {
|
||||||
|
return ErrInvalidPrerelease
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the spec, "Build metadata MAY be denoted by
|
||||||
|
// appending a plus sign and a series of dot separated identifiers immediately
|
||||||
|
// following the patch or pre-release version. Identifiers MUST comprise only
|
||||||
|
// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty."
|
||||||
|
func validateMetadata(m string) error {
|
||||||
|
eparts := strings.Split(m, ".")
|
||||||
|
for _, p := range eparts {
|
||||||
|
if !containsOnly(p, allowed) {
|
||||||
|
return ErrInvalidMetadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -5,6 +5,9 @@ dario.cat/mergo
|
|||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
github.com/BurntSushi/toml
|
github.com/BurntSushi/toml
|
||||||
github.com/BurntSushi/toml/internal
|
github.com/BurntSushi/toml/internal
|
||||||
|
# github.com/Masterminds/semver/v3 v3.2.1
|
||||||
|
## explicit; go 1.18
|
||||||
|
github.com/Masterminds/semver/v3
|
||||||
# github.com/Microsoft/go-winio v0.6.1
|
# github.com/Microsoft/go-winio v0.6.1
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/Microsoft/go-winio
|
github.com/Microsoft/go-winio
|
||||||
|
Reference in New Issue
Block a user