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  }