github.com/opentofu/opentofu@v1.7.1/internal/plugin/discovery/version_set.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package discovery 7 8 import ( 9 "sort" 10 11 version "github.com/hashicorp/go-version" 12 ) 13 14 // A ConstraintStr is a string containing a possibly-invalid representation 15 // of a version constraint provided in configuration. Call Parse on it to 16 // obtain a real Constraint object, or discover that it is invalid. 17 type ConstraintStr string 18 19 // Parse transforms a ConstraintStr into a Constraints if it is 20 // syntactically valid. If it isn't then an error is returned instead. 21 func (s ConstraintStr) Parse() (Constraints, error) { 22 raw, err := version.NewConstraint(string(s)) 23 if err != nil { 24 return Constraints{}, err 25 } 26 return Constraints{raw}, nil 27 } 28 29 // MustParse is like Parse but it panics if the constraint string is invalid. 30 func (s ConstraintStr) MustParse() Constraints { 31 ret, err := s.Parse() 32 if err != nil { 33 panic(err) 34 } 35 return ret 36 } 37 38 // Constraints represents a set of versions which any given Version is either 39 // a member of or not. 40 type Constraints struct { 41 raw version.Constraints 42 } 43 44 // NewConstraints creates a Constraints based on a version.Constraints. 45 func NewConstraints(c version.Constraints) Constraints { 46 return Constraints{c} 47 } 48 49 // AllVersions is a Constraints containing all versions 50 var AllVersions Constraints 51 52 func init() { 53 AllVersions = Constraints{ 54 raw: make(version.Constraints, 0), 55 } 56 } 57 58 // Allows returns true if the given version permitted by the receiving 59 // constraints set. 60 func (s Constraints) Allows(v Version) bool { 61 return s.raw.Check(v.raw) 62 } 63 64 // Append combines the receiving set with the given other set to produce 65 // a set that is the intersection of both sets, which is to say that resulting 66 // constraints contain only the versions that are members of both. 67 func (s Constraints) Append(other Constraints) Constraints { 68 raw := make(version.Constraints, 0, len(s.raw)+len(other.raw)) 69 70 // Since "raw" is a list of constraints that remove versions from the set, 71 // "Intersection" is implemented by concatenating together those lists, 72 // thus leaving behind only the versions not removed by either list. 73 raw = append(raw, s.raw...) 74 raw = append(raw, other.raw...) 75 76 // while the set is unordered, we sort these lexically for consistent output 77 sort.Slice(raw, func(i, j int) bool { 78 return raw[i].String() < raw[j].String() 79 }) 80 81 return Constraints{raw} 82 } 83 84 // String returns a string representation of the set members as a set 85 // of range constraints. 86 func (s Constraints) String() string { 87 return s.raw.String() 88 } 89 90 // Unconstrained returns true if and only if the receiver is an empty 91 // constraint set. 92 func (s Constraints) Unconstrained() bool { 93 return len(s.raw) == 0 94 }