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.IO (BufferMode (LineBuffering), hSetBuffering)
32-- | Flags passed in from the command line.
33data BuildFlags = BuildFlags
34 { bfEnableTests :: !Bool
36 , bfEnableLibProfile :: !Bool
40data BuildType = Nightly | LTS BumpType
41 deriving (Show, Read, Eq, Ord)
43data BumpType = Major | Minor
44 deriving (Show, Read, Eq, Ord)
46data Settings = Settings
48 , planFile :: FilePath
49 , buildDir :: FilePath
51 , title :: Text -> Text -- ^ GHC version -> title
53 , setArgs :: Text -> UploadBundle -> UploadBundle
57nightlyPlanFile :: Text -- ^ day
59nightlyPlanFile day = fpFromText ("nightly-" ++ day) <.> "yaml"
61nightlySettings :: Text -- ^ day
64nightlySettings day plan' = Settings
65 { planFile = nightlyPlanFile day
66 , buildDir = fpFromText $ "builds/stackage-nightly-" ++ day
67 , logDir = fpFromText $ "logs/stackage-nightly-" ++ day
68 , title = \ghcVer -> concat
75 , setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
77 , postBuild = return ()
80 slug' = "nightly-" ++ day
82getSettings :: Manager -> BuildType -> IO Settings
83getSettings man Nightly = do
84 day <- tshow . utctDay <$> getCurrentTime
85 bc <- defaultBuildConstraints man
86 pkgs <- getLatestAllowedPlans bc
87 plan' <- newBuildPlan pkgs bc
88 return $ nightlySettings day plan'
89getSettings man (LTS bumpType) = do
90 Option mlts <- fmap (fmap getMax) $ runResourceT
92 $$ foldMapC (Option . fmap Max . parseLTSVer . filename)
94 (new, plan') <- case bumpType of
99 Just (LTSVer x _) -> LTSVer (x + 1) 0
100 bc <- defaultBuildConstraints man
101 pkgs <- getLatestAllowedPlans bc
102 plan' <- newBuildPlan pkgs bc
105 old <- maybe (error "No LTS plans found in current directory") return mlts
106 oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
107 >>= either throwM return
108 let new = incrLTSVer old
109 let bc = updateBuildConstraints oldplan
110 pkgs <- getLatestAllowedPlans bc
111 plan' <- newBuildPlan pkgs bc
114 let newfile = renderLTSVer new
118 , buildDir = fpFromText $ "builds/stackage-lts-" ++ tshow new
119 , logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
120 , title = \ghcVer -> concat
126 , slug = "lts-" ++ tshow new
127 , setArgs = \_ ub -> ub { ubLTS = Just $ tshow new }
130 let git args = withCheckedProcess
131 (proc "git" args) $ \ClosedStream Inherited Inherited ->
133 putStrLn "Committing new LTS file to Git"
134 git ["add", fpToString newfile]
135 git ["commit", "-m", "Added new LTS release: " ++ show new]
136 putStrLn "Pushing to Git repository"
140data LTSVer = LTSVer !Int !Int
142instance Show LTSVer where
143 show (LTSVer x y) = concat [show x, ".", show y]
144incrLTSVer :: LTSVer -> LTSVer
145incrLTSVer (LTSVer x y) = LTSVer x (y + 1)
147parseLTSVer :: FilePath -> Maybe LTSVer
149 w <- stripPrefix "lts-" $ fpToText fp
150 x <- stripSuffix ".yaml" w
151 Right (major, y) <- Just $ decimal x
152 z <- stripPrefix "." y
153 Right (minor, "") <- Just $ decimal z
154 return $ LTSVer major minor
155renderLTSVer :: LTSVer -> FilePath
156renderLTSVer lts = fpFromText $ concat
162-- | Just print a message saying "still alive" every minute, to appease Travis.
163stillAlive :: IO () -> IO ()
165 withAsync (printer 1) $ const inner
167 printer i = forever $ do
169 putStrLn $ "Still alive: " ++ tshow i
172-- | Generate and check a new build plan, but do not execute it.
176justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
177 putStrLn "Loading build constraints"
178 bc <- defaultBuildConstraints man
180 putStrLn "Creating build plan"
181 plans <- getLatestAllowedPlans bc
182 plan <- newBuildPlan plans bc
184 putStrLn $ "Writing build plan to check-plan.yaml"
185 encodeFile "check-plan.yaml" plan
187 putStrLn "Checking plan"
190 putStrLn "Plan seems valid!"
192getPerformBuild :: BuildFlags -> Settings -> PerformBuild
193getPerformBuild buildFlags Settings {..} = PerformBuild
195 , pbInstallDest = buildDir
197 , pbLog = hPut stdout
199 , pbGlobalInstall = False
200 , pbEnableTests = bfEnableTests buildFlags
201 , pbEnableLibProfiling = bfEnableLibProfile buildFlags
202 , pbVerbose = bfVerbose buildFlags
205-- | Make a complete plan, build, test and upload bundle, docs and
207completeBuild :: BuildType -> BuildFlags -> IO ()
208completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
209 hSetBuffering stdout LineBuffering
211 putStrLn $ "Loading settings for: " ++ tshow buildType
212 settings@Settings {..} <- getSettings man buildType
214 putStrLn $ "Writing build plan to: " ++ fpToText planFile
215 encodeFile (fpToString planFile) plan
217 putStrLn "Checking build plan"
220 putStrLn "Performing build"
221 performBuild (getPerformBuild buildFlags settings) >>= mapM_ putStrLn
223 when (bfDoUpload buildFlags) $
224 finallyUpload settings man
227 :: Text -- ^ nightly date
229justUploadNightly day = do
230 plan <- decodeFileEither (fpToString $ nightlyPlanFile day)
231 >>= either throwM return
232 withManager tlsManagerSettings $ finallyUpload $ nightlySettings day plan
234-- | The final part of the complete build process: uploading a bundle,
235-- docs and a distro to hackage.
236finallyUpload :: Settings -> Manager -> IO ()
237finallyUpload settings@Settings{..} man = do
238 putStrLn "Uploading bundle to Stackage Server"
239 token <- readFile "/auth-token"
241 let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
242 (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
243 { ubContents = serverBundle now (title ghcVer) slug plan
244 , ubAuthToken = decodeUtf8 token
246 putStrLn $ "New ident: " ++ unSnapshotIdent ident
248 putStrLn $ "Track progress at: " ++ loc
250 postBuild `catchAny` print
252 putStrLn "Uploading docs to Stackage Server"
253 res1 <- uploadDocs UploadDocs
255 , udAuthToken = decodeUtf8 token
256 , udDocs = pbDocDir pb
259 putStrLn $ "Doc upload response: " ++ tshow res1
261 ecreds <- tryIO $ readFile "/hackage-creds"
262 case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
263 [username, password] -> do
264 putStrLn "Uploading as Hackage distro"
265 res2 <- uploadHackageDistro plan username password man
266 putStrLn $ "Distro upload response: " ++ tshow res2
267 _ -> putStrLn "No creds found, skipping Hackage distro upload"
269 putStrLn "Uploading doc map"
270 uploadDocMap UploadDocMap
272 , udmAuthToken = decodeUtf8 token
273 , udmSnapshot = ident
274 , udmDocDir = pbDocDir pb
278 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