forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathResolver.hs
More file actions
143 lines (130 loc) · 4.85 KB
/
Copy pathResolver.hs
File metadata and controls
143 lines (130 loc) · 4.85 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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE UndecidableInstances #-}
module Stack.Types.Resolver
(AbstractResolver(..)
,readAbstractResolver
,SnapName(..)
,Snapshots (..)
,renderSnapName
,parseSnapName
) where
import Data.Aeson.Extended
(FromJSON, parseJSON,
withObject, (.:), withText)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.IntMap.Strict as IntMap
import qualified Data.Text as T
import Data.Text.Read (decimal)
import Data.Time (Day)
import Options.Applicative (ReadM)
import qualified Options.Applicative.Types as OA
import Stack.Prelude
-- | Either an actual resolver value, or an abstract description of one (e.g.,
-- latest nightly).
data AbstractResolver
= ARLatestNightly
| ARLatestLTS
| ARLatestLTSMajor !Int
| ARResolver !RawSnapshotLocation
| ARGlobal
instance Show AbstractResolver where
show = T.unpack . utf8BuilderToText . display
instance Display AbstractResolver where
display ARLatestNightly = "nightly"
display ARLatestLTS = "lts"
display (ARLatestLTSMajor x) = "lts-" <> display x
display (ARResolver usl) = display usl
display ARGlobal = "global"
readAbstractResolver :: ReadM (Unresolved AbstractResolver)
readAbstractResolver = do
s <- OA.readerAsk
case s of
"global" -> pure $ pure ARGlobal
"nightly" -> pure $ pure ARLatestNightly
"lts" -> pure $ pure ARLatestLTS
'l':'t':'s':'-':x | Right (x', "") <- decimal $ T.pack x ->
pure $ pure $ ARLatestLTSMajor x'
_ -> pure $ ARResolver <$> parseRawSnapshotLocation (T.pack s)
-- | The name of an LTS Haskell or Stackage Nightly snapshot.
data SnapName
= LTS !Int !Int
| Nightly !Day
deriving (Generic, Typeable, Show, Data, Eq)
instance NFData SnapName
instance Display SnapName where
display = display . renderSnapName
data BuildPlanTypesException
= ParseSnapNameException !Text
| ParseResolverException !Text
| FilepathInDownloadedSnapshot !Text
deriving Typeable
instance Exception BuildPlanTypesException
instance Show BuildPlanTypesException where
show (ParseSnapNameException t) = "Invalid snapshot name: " ++ T.unpack t
show (ParseResolverException t) = concat
[ "Invalid resolver value: "
, T.unpack t
, ". Possible valid values include lts-2.12, nightly-YYYY-MM-DD, ghc-7.10.2, and ghcjs-0.1.0_ghc-7.10.2. "
, "See https://www.stackage.org/snapshots for a complete list."
]
show (FilepathInDownloadedSnapshot url) = unlines
[ "Downloaded snapshot specified a 'resolver: { location: filepath }' "
, "field, but filepaths are not allowed in downloaded snapshots.\n"
, "Filepath specified: " ++ T.unpack url
]
-- | Convert a 'SnapName' into its short representation, e.g. @lts-2.8@,
-- @nightly-2015-03-05@.
renderSnapName :: SnapName -> Text
renderSnapName (LTS x y) = T.pack $ concat ["lts-", show x, ".", show y]
renderSnapName (Nightly d) = T.pack $ "nightly-" ++ show d
-- | Parse the short representation of a 'SnapName'.
parseSnapName :: MonadThrow m => Text -> m SnapName
parseSnapName t0 =
case lts <|> nightly of
Nothing -> throwM $ ParseSnapNameException t0
Just sn -> return sn
where
lts = do
t1 <- T.stripPrefix "lts-" t0
Right (x, t2) <- Just $ decimal t1
t3 <- T.stripPrefix "." t2
Right (y, "") <- Just $ decimal t3
return $ LTS x y
nightly = do
t1 <- T.stripPrefix "nightly-" t0
Nightly <$> readMaybe (T.unpack t1)
-- | Most recent Nightly and newest LTS version per major release.
data Snapshots = Snapshots
{ snapshotsNightly :: !Day
, snapshotsLts :: !(IntMap Int)
}
deriving Show
instance FromJSON Snapshots where
parseJSON = withObject "Snapshots" $ \o -> Snapshots
<$> (o .: "nightly" >>= parseNightly)
<*> fmap IntMap.unions (mapM (parseLTS . snd)
$ filter (isLTS . fst)
$ HashMap.toList o)
where
parseNightly t =
case parseSnapName t of
Left e -> fail $ show e
Right (LTS _ _) -> fail "Unexpected LTS value"
Right (Nightly d) -> return d
isLTS = ("lts-" `T.isPrefixOf`)
parseLTS = withText "LTS" $ \t ->
case parseSnapName t of
Left e -> fail $ show e
Right (LTS x y) -> return $ IntMap.singleton x y
Right (Nightly _) -> fail "Unexpected nightly value"