getproviders: Normalize versions before dedupe
When rendering a set of version constraints to a string, we normalize partially-constrained versions. This means converting a version like 2.68.* to 2.68.0. Prior to this commit, this normalization was done after deduplication. This could result in a version constraints string with duplicate entries, if multiple partially-constrained versions are equivalent. This commit fixes this by normalizing before deduplicating and sorting.
This commit is contained in:
parent
3ed08e3566
commit
b1bc0e5d92
|
@ -407,7 +407,18 @@ func VersionConstraintsString(spec VersionConstraints) string {
|
|||
// and sort them into a consistent order.
|
||||
sels := make(map[constraints.SelectionSpec]struct{})
|
||||
for _, sel := range spec {
|
||||
sels[sel] = struct{}{}
|
||||
// The parser allows writing abbreviated version (such as 2) which
|
||||
// end up being represented in memory with trailing unconstrained parts
|
||||
// (for example 2.*.*). For the purpose of serialization with Ruby
|
||||
// style syntax, these unconstrained parts can all be represented as 0
|
||||
// with no loss of meaning, so we make that conversion here. Doing so
|
||||
// allows us to deduplicate equivalent constraints, such as >= 2.0 and
|
||||
// >= 2.0.0.
|
||||
normalizedSel := constraints.SelectionSpec{
|
||||
Operator: sel.Operator,
|
||||
Boundary: sel.Boundary.ConstrainToZero(),
|
||||
}
|
||||
sels[normalizedSel] = struct{}{}
|
||||
}
|
||||
selsOrder := make([]constraints.SelectionSpec, 0, len(sels))
|
||||
for sel := range sels {
|
||||
|
@ -450,34 +461,26 @@ func VersionConstraintsString(spec VersionConstraints) string {
|
|||
b.WriteString("??? ")
|
||||
}
|
||||
|
||||
// The parser allows writing abbreviated version (such as 2) which
|
||||
// end up being represented in memory with trailing unconstrained parts
|
||||
// (for example 2.*.*). For the purpose of serialization with Ruby
|
||||
// style syntax, these unconstrained parts can all be represented as 0
|
||||
// with no loss of meaning, so we make that conversion here.
|
||||
//
|
||||
// This is possible because we use a different constraint operator to
|
||||
// distinguish between the two types of pessimistic constraint:
|
||||
// minor-only and patch-only. For minor-only constraints, we always
|
||||
// want to display only the major and minor version components, so we
|
||||
// special-case that operator below.
|
||||
// We use a different constraint operator to distinguish between the
|
||||
// two types of pessimistic constraint: minor-only and patch-only. For
|
||||
// minor-only constraints, we always want to display only the major and
|
||||
// minor version components, so we special-case that operator below.
|
||||
//
|
||||
// One final edge case is a minor-only constraint specified with only
|
||||
// the major version, such as ~> 2. We treat this the same as ~> 2.0,
|
||||
// because a major-only pessimistic constraint does not exist: it is
|
||||
// logically identical to >= 2.0.0.
|
||||
boundary := sel.Boundary.ConstrainToZero()
|
||||
if sel.Operator == constraints.OpGreaterThanOrEqualMinorOnly {
|
||||
// The minor-pessimistic syntax uses only two version components.
|
||||
fmt.Fprintf(&b, "%s.%s", boundary.Major, boundary.Minor)
|
||||
fmt.Fprintf(&b, "%s.%s", sel.Boundary.Major, sel.Boundary.Minor)
|
||||
} else {
|
||||
fmt.Fprintf(&b, "%s.%s.%s", boundary.Major, boundary.Minor, boundary.Patch)
|
||||
fmt.Fprintf(&b, "%s.%s.%s", sel.Boundary.Major, sel.Boundary.Minor, sel.Boundary.Patch)
|
||||
}
|
||||
if sel.Boundary.Prerelease != "" {
|
||||
b.WriteString("-" + boundary.Prerelease)
|
||||
b.WriteString("-" + sel.Boundary.Prerelease)
|
||||
}
|
||||
if sel.Boundary.Metadata != "" {
|
||||
b.WriteString("+" + boundary.Metadata)
|
||||
b.WriteString("+" + sel.Boundary.Metadata)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
|
|
|
@ -53,6 +53,10 @@ func TestVersionConstraintsString(t *testing.T) {
|
|||
MustParseVersionConstraints(">= 1.2.3, 1.2.3, ~> 1.2, 1.2.3"),
|
||||
"~> 1.2, >= 1.2.3, 1.2.3",
|
||||
},
|
||||
"equivalent duplicates removed": {
|
||||
MustParseVersionConstraints(">= 2.68, >= 2.68.0"),
|
||||
">= 2.68.0",
|
||||
},
|
||||
"consistent ordering, exhaustive": {
|
||||
// This weird jumble is just to exercise the different sort
|
||||
// ordering codepaths. Hopefully nothing quite this horrific
|
||||
|
|
Loading…
Reference in New Issue