1module Distribution.Types.VersionRange ( 2 -- * Version ranges 3 VersionRange, 4 5 -- ** Constructing 6 anyVersion, noVersion, 7 thisVersion, notThisVersion, 8 laterVersion, earlierVersion, 9 orLaterVersion, orEarlierVersion, 10 unionVersionRanges, intersectVersionRanges, 11 withinVersion, 12 majorBoundVersion, 13 14 -- ** Inspection 15 -- 16 -- See "Distribution.Version" for more utilities. 17 withinRange, 18 foldVersionRange, 19 normaliseVersionRange, 20 stripParensVersionRange, 21 hasUpperBound, 22 hasLowerBound, 23 24 -- ** Cata & ana 25 VersionRangeF (..), 26 cataVersionRange, 27 anaVersionRange, 28 hyloVersionRange, 29 projectVersionRange, 30 embedVersionRange, 31 32 -- ** Utilities 33 isAnyVersion, 34 isAnyVersionLight, 35 wildcardUpperBound, 36 majorUpperBound, 37 isWildcardRange, 38 versionRangeParser, 39 ) where 40 41import Distribution.Compat.Prelude 42import Distribution.Types.Version 43import Distribution.Types.VersionInterval 44import Distribution.Types.VersionRange.Internal 45import Prelude () 46 47-- | Fold over the basic syntactic structure of a 'VersionRange'. 48-- 49-- This provides a syntactic view of the expression defining the version range. 50-- The syntactic sugar @\">= v\"@, @\"<= v\"@ and @\"== v.*\"@ is presented 51-- in terms of the other basic syntax. 52-- 53-- For a semantic view use 'asVersionIntervals'. 54-- 55foldVersionRange :: a -- ^ @\"-any\"@ version 56 -> (Version -> a) -- ^ @\"== v\"@ 57 -> (Version -> a) -- ^ @\"> v\"@ 58 -> (Version -> a) -- ^ @\"< v\"@ 59 -> (a -> a -> a) -- ^ @\"_ || _\"@ union 60 -> (a -> a -> a) -- ^ @\"_ && _\"@ intersection 61 -> VersionRange -> a 62foldVersionRange _any this later earlier union intersect = fold 63 where 64 fold = cataVersionRange alg 65 66 alg (ThisVersionF v) = this v 67 alg (LaterVersionF v) = later v 68 alg (OrLaterVersionF v) = union (this v) (later v) 69 alg (EarlierVersionF v) = earlier v 70 alg (OrEarlierVersionF v) = union (this v) (earlier v) 71 alg (MajorBoundVersionF v) = fold (majorBound v) 72 alg (UnionVersionRangesF v1 v2) = union v1 v2 73 alg (IntersectVersionRangesF v1 v2) = intersect v1 v2 74 75 majorBound v = intersectVersionRanges 76 (orLaterVersion v) 77 (earlierVersion (majorUpperBound v)) 78 79-- | Normalise 'VersionRange'. 80-- 81-- In particular collapse @(== v || > v)@ into @>= v@, and so on. 82normaliseVersionRange :: VersionRange -> VersionRange 83normaliseVersionRange = hyloVersionRange embed projectVersionRange 84 where 85 -- == v || > v, > v || == v ==> >= v 86 embed (UnionVersionRangesF (ThisVersion v) (LaterVersion v')) | v == v' = 87 orLaterVersion v 88 embed (UnionVersionRangesF (LaterVersion v) (ThisVersion v')) | v == v' = 89 orLaterVersion v 90 91 -- == v || < v, < v || == v ==> <= v 92 embed (UnionVersionRangesF (ThisVersion v) (EarlierVersion v')) | v == v' = 93 orEarlierVersion v 94 embed (UnionVersionRangesF (EarlierVersion v) (ThisVersion v')) | v == v' = 95 orEarlierVersion v 96 97 -- otherwise embed normally 98 embed vr = embedVersionRange vr 99 100-- | Remove 'VersionRangeParens' constructors. 101-- 102-- Since version 3.4 this function is 'id', there aren't 'VersionRangeParens' constructor in 'VersionRange' anymore. 103-- 104-- @since 2.2 105stripParensVersionRange :: VersionRange -> VersionRange 106stripParensVersionRange = id 107 108-- | Does this version fall within the given range? 109-- 110-- This is the evaluation function for the 'VersionRange' type. 111-- 112withinRange :: Version -> VersionRange -> Bool 113withinRange v = foldVersionRange 114 True 115 (\v' -> v == v') 116 (\v' -> v > v') 117 (\v' -> v < v') 118 (||) 119 (&&) 120 121-- | Does this 'VersionRange' place any restriction on the 'Version' or is it 122-- in fact equivalent to 'AnyVersion'. 123-- 124-- Note this is a semantic check, not simply a syntactic check. So for example 125-- the following is @True@ (for all @v@). 126-- 127-- > isAnyVersion (EarlierVersion v `UnionVersionRanges` orLaterVersion v) 128-- 129isAnyVersion :: VersionRange -> Bool 130isAnyVersion vr = case asVersionIntervals vr of 131 [(LowerBound v InclusiveBound, NoUpperBound)] -> v == version0 132 _ -> False 133 134-- A fast and non-precise version of 'isAnyVersion', 135-- returns 'True' only for @>= 0@ 'VersionRange's. 136-- 137-- /Do not use/. The "VersionIntervals don't destroy MajorBoundVersion" 138-- https://github.com/haskell/cabal/pull/6736 pull-request 139-- will change 'simplifyVersionRange' to properly preserve semantics. 140-- Then we can use it to normalise 'VersionRange's in tests. 141-- 142isAnyVersionLight :: VersionRange -> Bool 143isAnyVersionLight (OrLaterVersion v) = v == version0 144isAnyVersionLight _vr = False 145 146---------------------------- 147-- Wildcard range utilities 148-- 149 150 151isWildcardRange :: Version -> Version -> Bool 152isWildcardRange ver1 ver2 = check (versionNumbers ver1) (versionNumbers ver2) 153 where check (n:[]) (m:[]) | n+1 == m = True 154 check (n:ns) (m:ms) | n == m = check ns ms 155 check _ _ = False 156 157-- | Does the version range have an upper bound? 158-- 159-- @since 1.24.0.0 160hasUpperBound :: VersionRange -> Bool 161hasUpperBound = foldVersionRange 162 False 163 (const True) 164 (const False) 165 (const True) 166 (&&) (||) 167 168-- | Does the version range have an explicit lower bound? 169-- 170-- Note: this function only considers the user-specified lower bounds, but not 171-- the implicit >=0 lower bound. 172-- 173-- @since 1.24.0.0 174hasLowerBound :: VersionRange -> Bool 175hasLowerBound = foldVersionRange 176 False 177 (const True) 178 (const True) 179 (const False) 180 (&&) (||) 181