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