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
38 , bfSkipCheck :: !Bool
41data BuildType = Nightly | LTS BumpType
42 deriving (Show, Read, Eq, Ord)
44data BumpType = Major | Minor
45 deriving (Show, Read, Eq, Ord)
47data Settings = Settings
49 , planFile :: FilePath
50 , buildDir :: FilePath
52 , title :: Text -> Text -- ^ GHC version -> title
54 , setArgs :: Text -> UploadBundle -> UploadBundle
58nightlyPlanFile :: Text -- ^ day
60nightlyPlanFile day = fpFromText ("nightly-" ++ day) <.> "yaml"
62nightlySettings :: Text -- ^ day
65nightlySettings day plan' = Settings
66 { planFile = nightlyPlanFile day
67 , buildDir = fpFromText $ "builds/stackage-nightly-" ++ day
68 , logDir = fpFromText $ "logs/stackage-nightly-" ++ day
69 , title = \ghcVer -> concat
76 , setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
78 , postBuild = return ()
81 slug' = "nightly-" ++ day
83getSettings :: Manager -> BuildType -> IO Settings
84getSettings man Nightly = do
85 day <- tshow . utctDay <$> getCurrentTime
86 bc <- defaultBuildConstraints man
87 pkgs <- getLatestAllowedPlans bc
88 plan' <- newBuildPlan pkgs bc
89 return $ nightlySettings day plan'
90getSettings man (LTS bumpType) = do
91 Option mlts <- fmap (fmap getMax) $ runResourceT
93 $$ foldMapC (Option . fmap Max . parseLTSVer . filename)
95 (new, plan') <- case bumpType of
100 Just (LTSVer x _) -> LTSVer (x + 1) 0
101 bc <- defaultBuildConstraints man
102 pkgs <- getLatestAllowedPlans bc
103 plan' <- newBuildPlan pkgs bc
106 old <- maybe (error "No LTS plans found in current directory") return mlts
107 oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
108 >>= either throwM return
109 let new = incrLTSVer old
110 let bc = updateBuildConstraints oldplan
111 pkgs <- getLatestAllowedPlans bc
112 plan' <- newBuildPlan pkgs bc
115 let newfile = renderLTSVer new
119 , buildDir = fpFromText $ "builds/stackage-lts-" ++ tshow new
120 , logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
121 , title = \ghcVer -> concat
127 , slug = "lts-" ++ tshow new
128 , setArgs = \_ ub -> ub { ubLTS = Just $ tshow new }
131 let git args = withCheckedProcess
132 (proc "git" args) $ \ClosedStream Inherited Inherited ->
134 putStrLn "Committing new LTS file to Git"
135 git ["add", fpToString newfile]
136 git ["commit", "-m", "Added new LTS release: " ++ show new]
137 putStrLn "Pushing to Git repository"
141data LTSVer = LTSVer !Int !Int
143instance Show LTSVer where
144 show (LTSVer x y) = concat [show x, ".", show y]
145incrLTSVer :: LTSVer -> LTSVer
146incrLTSVer (LTSVer x y) = LTSVer x (y + 1)
148parseLTSVer :: FilePath -> Maybe LTSVer
150 w <- stripPrefix "lts-" $ fpToText fp
151 x <- stripSuffix ".yaml" w
152 Right (major, y) <- Just $ decimal x
153 z <- stripPrefix "." y
154 Right (minor, "") <- Just $ decimal z
155 return $ LTSVer major minor
156renderLTSVer :: LTSVer -> FilePath
157renderLTSVer lts = fpFromText $ concat
163-- | Just print a message saying "still alive" every minute, to appease Travis.
164stillAlive :: IO () -> IO ()
166 withAsync (printer 1) $ const inner
168 printer i = forever $ do
170 putStrLn $ "Still alive: " ++ tshow i
173-- | Generate and check a new build plan, but do not execute it.
177justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
178 putStrLn "Loading build constraints"
179 bc <- defaultBuildConstraints man
181 putStrLn "Creating build plan"
182 plans <- getLatestAllowedPlans bc
183 plan <- newBuildPlan plans bc
185 putStrLn $ "Writing build plan to check-plan.yaml"
186 encodeFile "check-plan.yaml" plan
188 putStrLn "Checking plan"
191 putStrLn "Plan seems valid!"
193getPerformBuild :: BuildFlags -> Settings -> PerformBuild
194getPerformBuild buildFlags Settings {..} = PerformBuild
196 , pbInstallDest = buildDir
198 , pbLog = hPut stdout
200 , pbGlobalInstall = False
201 , pbEnableTests = bfEnableTests buildFlags
202 , pbEnableLibProfiling = bfEnableLibProfile buildFlags
203 , pbVerbose = bfVerbose buildFlags
204 , pbAllowNewer = bfSkipCheck buildFlags
207-- | Make a complete plan, build, test and upload bundle, docs and
209completeBuild :: BuildType -> BuildFlags -> IO ()
210completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
211 hSetBuffering stdout LineBuffering
213 putStrLn $ "Loading settings for: " ++ tshow buildType
214 settings@Settings {..} <- getSettings man buildType
216 putStrLn $ "Writing build plan to: " ++ fpToText planFile
217 encodeFile (fpToString planFile) plan
219 if bfSkipCheck buildFlags
220 then putStrLn "Skipping build plan check"
222 putStrLn "Checking build plan"
225 putStrLn "Performing build"
226 performBuild (getPerformBuild buildFlags settings) >>= mapM_ putStrLn
228 when (bfDoUpload buildFlags) $
229 finallyUpload settings man
232 :: Text -- ^ nightly date
234justUploadNightly day = do
235 plan <- decodeFileEither (fpToString $ nightlyPlanFile day)
236 >>= either throwM return
237 withManager tlsManagerSettings $ finallyUpload $ nightlySettings day plan
239-- | The final part of the complete build process: uploading a bundle,
240-- docs and a distro to hackage.
241finallyUpload :: Settings -> Manager -> IO ()
242finallyUpload settings@Settings{..} man = do
243 putStrLn "Uploading bundle to Stackage Server"
244 token <- readFile "/auth-token"
246 let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
247 (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
248 { ubContents = serverBundle now (title ghcVer) slug plan
249 , ubAuthToken = decodeUtf8 token
251 putStrLn $ "New ident: " ++ unSnapshotIdent ident
253 putStrLn $ "Track progress at: " ++ loc
255 postBuild `catchAny` print
257 putStrLn "Uploading docs to Stackage Server"
258 res1 <- uploadDocs UploadDocs
260 , udAuthToken = decodeUtf8 token
261 , udDocs = pbDocDir pb
264 putStrLn $ "Doc upload response: " ++ tshow res1
266 ecreds <- tryIO $ readFile "/hackage-creds"
267 case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
268 [username, password] -> do
269 putStrLn "Uploading as Hackage distro"
270 res2 <- uploadHackageDistro plan username password man
271 putStrLn $ "Distro upload response: " ++ tshow res2
272 _ -> putStrLn "No creds found, skipping Hackage distro upload"
274 putStrLn "Uploading doc map"
275 uploadDocMap UploadDocMap
277 , udmAuthToken = decodeUtf8 token
278 , udmSnapshot = ident
279 , udmDocDir = pbDocDir pb
283 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