comparator.scm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ;;; guile-semver --- Semantic Version tooling for guile
  2. ;;; Copyright © 2017 Jelle Dirk Licht <jlicht@fsfe.org>
  3. ;;;
  4. ;;; This file is part of guile-semver.
  5. ;;;
  6. ;;; guile-semver is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or
  9. ;;; (at your option) any later version.
  10. ;;;
  11. ;;; guile-semver is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;; General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with guile-semver. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (semver comparator)
  19. #:use-module (srfi srfi-67)
  20. #:use-module (ice-9 match)
  21. #:use-module (semver structs)
  22. #:export (semantic-version-compare
  23. *semantic-version-min*
  24. *semantic-version-max*
  25. semantic-version-wildcard-min
  26. semantic-version-wildcard-max))
  27. (define *semantic-version-min*
  28. (make-semantic-version 0 0 0 '(0) '(0)))
  29. (define *semantic-version-max*
  30. (make-semantic-version +inf.0 +inf.0 +inf.0 '() '()))
  31. (define (wildcard? part)
  32. (or (equal? part "X")
  33. (equal? part "x")
  34. (equal? part "*")))
  35. ;;; TODO
  36. ;; If a version has a prerelease tag (for example, 1.2.3-alpha.3) then
  37. ;; it will only be allowed to satisfy comparator sets if at least one
  38. ;; comparator with the same [major, minor, patch] tuple also has a
  39. ;; prerelease tag.
  40. ;; For example, the range >1.2.3-alpha.3 would be allowed to match the
  41. ;; version 1.2.3-alpha.7, but it would not be satisfied by
  42. ;; 3.4.5-alpha.9, even though 3.4.5-alpha.9 is technically "greater
  43. ;; than" 1.2.3-alpha.3 according to the SemVer sort rules. The version
  44. ;; range only accepts prerelease tags on the 1.2.3 version. The
  45. ;; version 3.4.5 would satisfy the range, because it does not have a
  46. ;; prerelease flag, and 3.4.5 is greater than 1.2.3-alpha.7.
  47. ;; The purpose for this behavior is twofold. First, prerelease
  48. ;; versions frequently are updated very quickly, and contain many
  49. ;; breaking changes that are (by the author's design) not yet fit for
  50. ;; public consumption. Therefore, by default, they are excluded from
  51. ;; range matching semantics.
  52. ;; Second, a user who has opted into using a prerelease version has
  53. ;; clearly indicated the intent to use that specific set of
  54. ;; alpha/beta/rc versions. By including a prerelease tag in the range,
  55. ;; the user is indicating that they are aware of the risk. However, it
  56. ;; is still not appropriate to assume that they have opted into taking
  57. ;; a similar risk on the next set of prerelease versions.
  58. (define* (semantic-version-wildcard-max major #:optional (minor "*") (patch "*") . _)
  59. (cond ((wildcard? major) ; Basically everything, except
  60. *semantic-version-max*)
  61. ((wildcard? minor)
  62. (make-semantic-version
  63. (string->number major) +inf.0 +inf.0 '() '()))
  64. ((wildcard? patch)
  65. (make-semantic-version
  66. (string->number major) (string->number minor) +inf.0 '() '()))
  67. ;; Last part is incorrect I guess?
  68. (else (inc-semantic-version (make-semantic-version* major minor patch)))))
  69. (define* (semantic-version-wildcard-min major #:optional (minor "*") (patch "*") . _)
  70. (cond ((wildcard? major) ; Basically everything, except
  71. *semantic-version-min*)
  72. ((wildcard? minor)
  73. (make-semantic-version
  74. (string->number major) 0 0 '(0) '(0)))
  75. ((wildcard? patch)
  76. (make-semantic-version
  77. (string->number major) (string->number minor) 0 '(0) '(0)))
  78. ;; Last part is incorrect I guess?
  79. (else (make-semantic-version* major minor patch))))
  80. (define (int-str-compare int-str1 int-str2)
  81. (match (list (string? int-str1)
  82. (number? int-str1)
  83. (string? int-str2)
  84. (number? int-str2))
  85. ((#t #f #t #f) (string-compare int-str1 int-str2))
  86. ((#t #f #f #t) 1)
  87. ((#f #t #t #f) -1)
  88. ((#f #t #f #t) (number-compare int-str1 int-str2))))
  89. (define (pre-release-compare pre-release1 pre-release2)
  90. (match (list (null? pre-release1)
  91. (null? pre-release2))
  92. ((#t #t) 0)
  93. ((#t #f) 1)
  94. ((#f #f)
  95. (list-compare int-str-compare pre-release1 pre-release2))
  96. ((#f #t) -1)))
  97. (define (semantic-version-compare semver1 semver2)
  98. (refine-compare
  99. (number-compare (semantic-version-major semver1)
  100. (semantic-version-major semver2))
  101. (number-compare (semantic-version-minor semver1)
  102. (semantic-version-minor semver2))
  103. (number-compare (semantic-version-patch semver1)
  104. (semantic-version-patch semver2))
  105. (pre-release-compare (semantic-version-pre-release semver1)
  106. (semantic-version-pre-release semver2))
  107. ;; The Semantic Version specification says we should not sort on
  108. ;; build data, but having a total order is still nice for plenty of
  109. ;; things. As this ends up being kind of arbitrary, we just re-use
  110. ;; the pre-release ordering for now.
  111. (pre-release-compare (semantic-version-build-metadata semver1)
  112. (semantic-version-build-metadata semver2))))