1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE RecordWildCards #-}
4module Stackage.CompleteBuild
13import Control.Concurrent (threadDelay)
14import Control.Concurrent.Async (withAsync)
15import Data.Default.Class (def)
16import Data.Semigroup (Max (..), Option (..))
17import Data.Text.Read (decimal)
19import Data.Yaml (decodeFileEither, encodeFile)
20import Network.HTTP.Client
21import Network.HTTP.Client.TLS (tlsManagerSettings)
22import Stackage.BuildConstraints
23import Stackage.BuildPlan
24import Stackage.CheckBuildPlan
25import Stackage.PerformBuild
26import Stackage.Prelude
27import Stackage.ServerBundle
28import Stackage.UpdateBuildPlan
30import System.Environment (lookupEnv)
31import System.IO (BufferMode (LineBuffering), hSetBuffering)
33-- | Flags passed in from the command line.
34data BuildFlags = BuildFlags
35 { bfEnableTests :: !Bool
37 , bfEnableLibProfile :: !Bool
39 , bfSkipCheck :: !Bool
42data BuildType = Nightly | LTS BumpType
43 deriving (Show, Read, Eq, Ord)
45data BumpType = Major | Minor
46 deriving (Show, Read, Eq, Ord)
48data Settings = Settings
50 , planFile :: FilePath
51 , buildDir :: FilePath
53 , title :: Text -> Text -- ^ GHC version -> title
55 , setArgs :: Text -> UploadBundle -> UploadBundle
57 , distroName :: Text -- ^ distro name on Hackage
60nightlyPlanFile :: Text -- ^ day
62nightlyPlanFile day = fpFromText ("nightly-" ++ day) <.> "yaml"
64nightlySettings :: Text -- ^ day
67nightlySettings day plan' = Settings
68 { planFile = nightlyPlanFile day
69 , buildDir = fpFromText $ "builds/stackage-nightly-" ++ day
70 , logDir = fpFromText $ "logs/stackage-nightly-" ++ day
71 , title = \ghcVer -> concat
78 , setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
80 , postBuild = return ()
81 , distroName = "Stackage"
84 slug' = "nightly-" ++ day
86getSettings :: Manager -> BuildType -> IO Settings
87getSettings man Nightly = do
88 day <- tshow . utctDay <$> getCurrentTime
89 bc <- defaultBuildConstraints man
90 pkgs <- getLatestAllowedPlans bc
91 plan' <- newBuildPlan pkgs bc
92 return $ nightlySettings day plan'
93getSettings man (LTS bumpType) = do
94 Option mlts <- fmap (fmap getMax) $ runResourceT
96 $$ foldMapC (Option . fmap Max . parseLTSVer . filename)
98 (new, plan') <- case bumpType of
102 Nothing -> LTSVer 0 0
103 Just (LTSVer x _) -> LTSVer (x + 1) 0
104 bc <- defaultBuildConstraints man
105 pkgs <- getLatestAllowedPlans bc
106 plan' <- newBuildPlan pkgs bc
109 old <- maybe (error "No LTS plans found in current directory") return mlts
110 oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
111 >>= either throwM return
112 let new = incrLTSVer old
113 let bc = updateBuildConstraints oldplan
114 pkgs <- getLatestAllowedPlans bc
115 plan' <- newBuildPlan pkgs bc
118 let newfile = renderLTSVer new
122 , buildDir = fpFromText $ "builds/stackage-lts-" ++ tshow new
123 , logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
124 , title = \ghcVer -> concat
130 , slug = "lts-" ++ tshow new
131 , setArgs = \_ ub -> ub { ubLTS = Just $ tshow new }
134 let git args = withCheckedProcess
135 (proc "git" args) $ \ClosedStream Inherited Inherited ->
137 putStrLn "Committing new LTS file to Git"
138 git ["add", fpToString newfile]
139 git ["commit", "-m", "Added new LTS release: " ++ show new]
140 putStrLn "Pushing to Git repository"
142 , distroName = "LTSHaskell"
145data LTSVer = LTSVer !Int !Int
147instance Show LTSVer where
148 show (LTSVer x y) = concat [show x, ".", show y]
149incrLTSVer :: LTSVer -> LTSVer
150incrLTSVer (LTSVer x y) = LTSVer x (y + 1)
152parseLTSVer :: FilePath -> Maybe LTSVer
154 w <- stripPrefix "lts-" $ fpToText fp
155 x <- stripSuffix ".yaml" w
156 Right (major, y) <- Just $ decimal x
157 z <- stripPrefix "." y
158 Right (minor, "") <- Just $ decimal z
159 return $ LTSVer major minor
160renderLTSVer :: LTSVer -> FilePath
161renderLTSVer lts = fpFromText $ concat
167-- | Just print a message saying "still alive" every minute, to appease Travis.
168stillAlive :: IO () -> IO ()
170 withAsync (printer 1) $ const inner
172 printer i = forever $ do
174 putStrLn $ "Still alive: " ++ tshow i
177-- | Generate and check a new build plan, but do not execute it.
181justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
182 putStrLn "Loading build constraints"
183 bc <- defaultBuildConstraints man
185 putStrLn "Creating build plan"
186 plans <- getLatestAllowedPlans bc
187 plan <- newBuildPlan plans bc
189 putStrLn $ "Writing build plan to check-plan.yaml"
190 encodeFile "check-plan.yaml" plan
192 putStrLn "Checking plan"
195 putStrLn "Plan seems valid!"
197getPerformBuild :: BuildFlags -> Settings -> PerformBuild
198getPerformBuild buildFlags Settings {..} = PerformBuild
200 , pbInstallDest = buildDir
202 , pbLog = hPut stdout
204 , pbGlobalInstall = False
205 , pbEnableTests = bfEnableTests buildFlags
206 , pbEnableLibProfiling = bfEnableLibProfile buildFlags
207 , pbVerbose = bfVerbose buildFlags
208 , pbAllowNewer = bfSkipCheck buildFlags
211-- | Make a complete plan, build, test and upload bundle, docs and
213completeBuild :: BuildType -> BuildFlags -> IO ()
214completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
215 hSetBuffering stdout LineBuffering
217 putStrLn $ "Loading settings for: " ++ tshow buildType
218 settings@Settings {..} <- getSettings man buildType
220 putStrLn $ "Writing build plan to: " ++ fpToText planFile
221 encodeFile (fpToString planFile) plan
223 if bfSkipCheck buildFlags
224 then putStrLn "Skipping build plan check"
226 putStrLn "Checking build plan"
229 putStrLn "Performing build"
230 performBuild (getPerformBuild buildFlags settings) >>= mapM_ putStrLn
232 when (bfDoUpload buildFlags) $
233 finallyUpload settings man
236 :: Text -- ^ nightly date
238justUploadNightly day = do
239 plan <- decodeFileEither (fpToString $ nightlyPlanFile day)
240 >>= either throwM return
241 withManager tlsManagerSettings $ finallyUpload $ nightlySettings day plan
243-- | The final part of the complete build process: uploading a bundle,
244-- docs and a distro to hackage.
245finallyUpload :: Settings -> Manager -> IO ()
246finallyUpload settings@Settings{..} man = do
247 putStrLn "Uploading bundle to Stackage Server"
249 mtoken <- lookupEnv "STACKAGE_AUTH_TOKEN"
252 Nothing -> decodeUtf8 <$> readFile "/auth-token"
253 Just token -> return $ pack token
256 let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
257 (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
258 { ubContents = serverBundle now (title ghcVer) slug plan
259 , ubAuthToken = token
261 putStrLn $ "New ident: " ++ unSnapshotIdent ident
263 putStrLn $ "Track progress at: " ++ loc
265 postBuild `catchAny` print
267 putStrLn "Uploading docs to Stackage Server"
268 res1 <- uploadDocs UploadDocs
270 , udAuthToken = token
271 , udDocs = pbDocDir pb
274 putStrLn $ "Doc upload response: " ++ tshow res1
276 ecreds <- tryIO $ readFile "/hackage-creds"
277 case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
278 [username, password] -> do
279 putStrLn "Uploading as Hackage distro"
280 res2 <- uploadHackageDistroNamed distroName plan username password man
281 putStrLn $ "Distro upload response: " ++ tshow res2
282 _ -> putStrLn "No creds found, skipping Hackage distro upload"
284 putStrLn "Uploading doc map"
285 uploadDocMap UploadDocMap
287 , udmAuthToken = token
288 , udmSnapshot = ident
289 , udmDocDir = pbDocDir pb
293 pb = getPerformBuild (error "finallyUpload.buildFlags") settings
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list