forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVersion.hs
More file actions
124 lines (106 loc) · 4.15 KB
/
Version.hs
File metadata and controls
124 lines (106 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
-- | Versions for packages.
module Stack.Types.Version
(Version
,Cabal.VersionRange -- TODO in the future should have a newtype wrapper
,IntersectingVersionRange(..)
,VersionCheck(..)
,versionRangeText
,withinRange
,Stack.Types.Version.intersectVersionRanges
,toMajorVersion
,latestApplicableVersion
,checkVersion
,nextMajorVersion
,minorVersion
,stackVersion
,stackMinorVersion)
where
import Stack.Prelude hiding (Vector)
import Pantry.Internal.AesonExtended
import Data.List (find)
import qualified Data.Set as Set
import qualified Data.Text as T
import Distribution.Text (disp)
import qualified Distribution.Version as Cabal
import Distribution.Version (Version, versionNumbers, withinRange)
import qualified Paths_stack as Meta
import Text.PrettyPrint (render)
newtype IntersectingVersionRange =
IntersectingVersionRange { getIntersectingVersionRange :: Cabal.VersionRange }
deriving Show
instance Semigroup IntersectingVersionRange where
IntersectingVersionRange l <> IntersectingVersionRange r =
IntersectingVersionRange (l `Cabal.intersectVersionRanges` r)
instance Monoid IntersectingVersionRange where
mempty = IntersectingVersionRange Cabal.anyVersion
mappend = (<>)
-- | Display a version range
versionRangeText :: Cabal.VersionRange -> Text
versionRangeText = T.pack . render . disp
-- | A modified intersection which also simplifies, for better display.
intersectVersionRanges :: Cabal.VersionRange -> Cabal.VersionRange -> Cabal.VersionRange
intersectVersionRanges x y = Cabal.simplifyVersionRange $ Cabal.intersectVersionRanges x y
-- | Returns the first two components, defaulting to 0 if not present
toMajorVersion :: Version -> Version
toMajorVersion v =
case versionNumbers v of
[] -> Cabal.mkVersion [0, 0]
[a] -> Cabal.mkVersion [a, 0]
a:b:_ -> Cabal.mkVersion [a, b]
-- | Given a version range and a set of versions, find the latest version from
-- the set that is within the range.
latestApplicableVersion :: Cabal.VersionRange -> Set Version -> Maybe Version
latestApplicableVersion r = find (`withinRange` r) . Set.toDescList
-- | Get the next major version number for the given version
nextMajorVersion :: Version -> Version
nextMajorVersion v =
case versionNumbers v of
[] -> Cabal.mkVersion [0, 1]
[a] -> Cabal.mkVersion [a, 1]
a:b:_ -> Cabal.mkVersion [a, b + 1]
data VersionCheck
= MatchMinor
| MatchExact
| NewerMinor
deriving (Show, Eq, Ord)
instance ToJSON VersionCheck where
toJSON MatchMinor = String "match-minor"
toJSON MatchExact = String "match-exact"
toJSON NewerMinor = String "newer-minor"
instance FromJSON VersionCheck where
parseJSON = withText expected $ \t ->
case t of
"match-minor" -> return MatchMinor
"match-exact" -> return MatchExact
"newer-minor" -> return NewerMinor
_ -> fail ("Expected " ++ expected ++ ", but got " ++ show t)
where
expected = "VersionCheck value (match-minor, match-exact, or newer-minor)"
checkVersion :: VersionCheck -> Version -> Version -> Bool
checkVersion check (versionNumbers -> wanted) (versionNumbers -> actual) =
case check of
MatchMinor -> and (take 3 matching)
MatchExact -> length wanted == length actual && and matching
NewerMinor -> and (take 2 matching) && newerMinor
where
matching = zipWith (==) wanted actual
getMinor (_a:_b:c:_) = Just c
getMinor _ = Nothing
newerMinor =
case (getMinor wanted, getMinor actual) of
(Nothing, _) -> True
(Just _, Nothing) -> False
(Just w, Just a) -> a >= w
-- | Get minor version (excludes any patchlevel)
minorVersion :: Version -> Version
minorVersion = Cabal.mkVersion . take 3 . versionNumbers
-- | Current Stack version
stackVersion :: Version
stackVersion = Cabal.mkVersion' Meta.version
-- | Current Stack minor version (excludes patchlevel)
stackMinorVersion :: Version
stackMinorVersion = minorVersion stackVersion