constraint.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package version
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. )
  7. // Constraint represents a single constraint for a version, such as
  8. // ">= 1.0".
  9. type Constraint struct {
  10. f constraintFunc
  11. check *Version
  12. original string
  13. }
  14. // Constraints is a slice of constraints. We make a custom type so that
  15. // we can add methods to it.
  16. type Constraints []*Constraint
  17. type constraintFunc func(v, c *Version) bool
  18. var constraintOperators map[string]constraintFunc
  19. var constraintRegexp *regexp.Regexp
  20. func init() {
  21. constraintOperators = map[string]constraintFunc{
  22. "": constraintEqual,
  23. "=": constraintEqual,
  24. "!=": constraintNotEqual,
  25. ">": constraintGreaterThan,
  26. "<": constraintLessThan,
  27. ">=": constraintGreaterThanEqual,
  28. "<=": constraintLessThanEqual,
  29. "~>": constraintPessimistic,
  30. }
  31. ops := make([]string, 0, len(constraintOperators))
  32. for k, _ := range constraintOperators {
  33. ops = append(ops, regexp.QuoteMeta(k))
  34. }
  35. constraintRegexp = regexp.MustCompile(fmt.Sprintf(
  36. `^\s*(%s)\s*(%s)\s*$`,
  37. strings.Join(ops, "|"),
  38. VersionRegexpRaw))
  39. }
  40. // NewConstraint will parse one or more constraints from the given
  41. // constraint string. The string must be a comma-separated list of
  42. // constraints.
  43. func NewConstraint(v string) (Constraints, error) {
  44. vs := strings.Split(v, ",")
  45. result := make([]*Constraint, len(vs))
  46. for i, single := range vs {
  47. c, err := parseSingle(single)
  48. if err != nil {
  49. return nil, err
  50. }
  51. result[i] = c
  52. }
  53. return Constraints(result), nil
  54. }
  55. // Check tests if a version satisfies all the constraints.
  56. func (cs Constraints) Check(v *Version) bool {
  57. for _, c := range cs {
  58. if !c.Check(v) {
  59. return false
  60. }
  61. }
  62. return true
  63. }
  64. // Returns the string format of the constraints
  65. func (cs Constraints) String() string {
  66. csStr := make([]string, len(cs))
  67. for i, c := range cs {
  68. csStr[i] = c.String()
  69. }
  70. return strings.Join(csStr, ",")
  71. }
  72. // Check tests if a constraint is validated by the given version.
  73. func (c *Constraint) Check(v *Version) bool {
  74. return c.f(v, c.check)
  75. }
  76. func (c *Constraint) String() string {
  77. return c.original
  78. }
  79. func parseSingle(v string) (*Constraint, error) {
  80. matches := constraintRegexp.FindStringSubmatch(v)
  81. if matches == nil {
  82. return nil, fmt.Errorf("Malformed constraint: %s", v)
  83. }
  84. check, err := NewVersion(matches[2])
  85. if err != nil {
  86. return nil, err
  87. }
  88. return &Constraint{
  89. f: constraintOperators[matches[1]],
  90. check: check,
  91. original: v,
  92. }, nil
  93. }
  94. //-------------------------------------------------------------------
  95. // Constraint functions
  96. //-------------------------------------------------------------------
  97. func constraintEqual(v, c *Version) bool {
  98. return v.Equal(c)
  99. }
  100. func constraintNotEqual(v, c *Version) bool {
  101. return !v.Equal(c)
  102. }
  103. func constraintGreaterThan(v, c *Version) bool {
  104. return v.Compare(c) == 1
  105. }
  106. func constraintLessThan(v, c *Version) bool {
  107. return v.Compare(c) == -1
  108. }
  109. func constraintGreaterThanEqual(v, c *Version) bool {
  110. return v.Compare(c) >= 0
  111. }
  112. func constraintLessThanEqual(v, c *Version) bool {
  113. return v.Compare(c) <= 0
  114. }
  115. func constraintPessimistic(v, c *Version) bool {
  116. if v.LessThan(c) {
  117. return false
  118. }
  119. for i := 0; i < c.si-1; i++ {
  120. if v.segments[i] != c.segments[i] {
  121. return false
  122. }
  123. }
  124. return true
  125. }