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
36 , bfEnableHaddock :: !Bool
38 , bfEnableLibProfile :: !Bool
39 , bfEnableExecDyn :: !Bool
41 , bfSkipCheck :: !Bool
44data BuildType = Nightly | LTS BumpType
45 deriving (Show, Read, Eq, Ord)
47data BumpType = Major | Minor
48 deriving (Show, Read, Eq, Ord)
50data Settings = Settings
52 , planFile :: FilePath
53 , buildDir :: FilePath
55 , title :: Text -> Text -- ^ GHC version -> title
57 , setArgs :: Text -> UploadBundle -> UploadBundle
59 , distroName :: Text -- ^ distro name on Hackage
60 , snapshotType :: SnapshotType
61 , bundleDest :: FilePath
64nightlyPlanFile :: Text -- ^ day
66nightlyPlanFile day = fpFromText ("nightly-" ++ day) <.> "yaml"
68nightlySettings :: Text -- ^ day
71nightlySettings day plan' = Settings
72 { planFile = nightlyPlanFile day
73 , buildDir = fpFromText $ "builds/nightly"
74 , logDir = fpFromText $ "logs/stackage-nightly-" ++ day
75 , title = \ghcVer -> concat
82 , setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
84 , postBuild = return ()
85 , distroName = "Stackage"
86 , snapshotType = STNightly
87 , bundleDest = fpFromText $ "stackage-nightly-" ++ day ++ ".bundle"
90 slug' = "nightly-" ++ day
92getSettings :: Manager -> BuildType -> IO Settings
93getSettings man Nightly = do
94 day <- tshow . utctDay <$> getCurrentTime
95 bc <- defaultBuildConstraints man
96 pkgs <- getLatestAllowedPlans bc
97 plan' <- newBuildPlan pkgs bc
98 return $ nightlySettings day plan'
99getSettings man (LTS bumpType) = do
100 Option mlts <- fmap (fmap getMax) $ runResourceT
101 $ sourceDirectory "."
102 $$ foldMapC (Option . fmap Max . parseLTSVer . filename)
104 (new, plan') <- case bumpType of
108 Nothing -> LTSVer 0 0
109 Just (LTSVer x _) -> LTSVer (x + 1) 0
110 bc <- defaultBuildConstraints man
111 pkgs <- getLatestAllowedPlans bc
112 plan' <- newBuildPlan pkgs bc
115 old <- maybe (error "No LTS plans found in current directory") return mlts
116 oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
117 >>= either throwM return
118 let new = incrLTSVer old
119 let bc = updateBuildConstraints oldplan
120 pkgs <- getLatestAllowedPlans bc
121 plan' <- newBuildPlan pkgs bc
124 let newfile = renderLTSVer new
128 , buildDir = fpFromText $ "builds/lts"
129 , logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
130 , title = \ghcVer -> concat
136 , slug = "lts-" ++ tshow new
137 , setArgs = \_ ub -> ub { ubLTS = Just $ tshow new }
140 let git args = withCheckedProcess
141 (proc "git" args) $ \ClosedStream Inherited Inherited ->
143 putStrLn "Committing new LTS file to Git"
144 git ["add", fpToString newfile]
145 git ["commit", "-m", "Added new LTS release: " ++ show new]
146 putStrLn "Pushing to Git repository"
148 , distroName = "LTSHaskell"
151 LTSVer x y -> STLTS x y
152 , bundleDest = fpFromText $ "stackage-lts-" ++ tshow new ++ ".bundle"
155data LTSVer = LTSVer !Int !Int
157instance Show LTSVer where
158 show (LTSVer x y) = concat [show x, ".", show y]
159incrLTSVer :: LTSVer -> LTSVer
160incrLTSVer (LTSVer x y) = LTSVer x (y + 1)
162parseLTSVer :: FilePath -> Maybe LTSVer
164 w <- stripPrefix "lts-" $ fpToText fp
165 x <- stripSuffix ".yaml" w
166 Right (major, y) <- Just $ decimal x
167 z <- stripPrefix "." y
168 Right (minor, "") <- Just $ decimal z
169 return $ LTSVer major minor
170renderLTSVer :: LTSVer -> FilePath
171renderLTSVer lts = fpFromText $ concat
177-- | Just print a message saying "still alive" every minute, to appease Travis.
178stillAlive :: IO () -> IO ()
180 withAsync (printer 1) $ const inner
182 printer i = forever $ do
184 putStrLn $ "Still alive: " ++ tshow i
187-- | Generate and check a new build plan, but do not execute it.
191justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
192 putStrLn "Loading build constraints"
193 bc <- defaultBuildConstraints man
195 putStrLn "Creating build plan"
196 plans <- getLatestAllowedPlans bc
197 plan <- newBuildPlan plans bc
199 putStrLn $ "Writing build plan to check-plan.yaml"
200 encodeFile "check-plan.yaml" plan
202 putStrLn "Checking plan"
205 putStrLn "Plan seems valid!"
207getPerformBuild :: BuildFlags -> Settings -> PerformBuild
208getPerformBuild buildFlags Settings {..} = PerformBuild
210 , pbInstallDest = buildDir
212 , pbLog = hPut stdout
214 , pbGlobalInstall = False
215 , pbEnableTests = bfEnableTests buildFlags
216 , pbEnableHaddock = bfEnableHaddock buildFlags
217 , pbEnableLibProfiling = bfEnableLibProfile buildFlags
218 , pbEnableExecDyn = bfEnableExecDyn buildFlags
219 , pbVerbose = bfVerbose buildFlags
220 , pbAllowNewer = bfSkipCheck buildFlags
223-- | Make a complete plan, build, test and upload bundle, docs and
225completeBuild :: BuildType -> BuildFlags -> IO ()
226completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
227 hSetBuffering stdout LineBuffering
229 putStrLn $ "Loading settings for: " ++ tshow buildType
230 settings@Settings {..} <- getSettings man buildType
232 putStrLn $ "Writing build plan to: " ++ fpToText planFile
233 encodeFile (fpToString planFile) plan
235 if bfSkipCheck buildFlags
236 then putStrLn "Skipping build plan check"
238 putStrLn "Checking build plan"
241 putStrLn "Performing build"
242 let pb = getPerformBuild buildFlags settings
243 performBuild pb >>= mapM_ putStrLn
245 putStrLn $ "Creating bundle (v2) at: " ++ fpToText bundleDest
246 createBundleV2 CreateBundleV2
248 , cb2Type = snapshotType
249 , cb2DocsDir = pbDocDir pb
250 , cb2Dest = bundleDest
253 when (bfDoUpload buildFlags) $
254 finallyUpload settings man
257 :: Text -- ^ nightly date
259justUploadNightly day = do
260 plan <- decodeFileEither (fpToString $ nightlyPlanFile day)
261 >>= either throwM return
262 withManager tlsManagerSettings $ finallyUpload $ nightlySettings day plan
264-- | The final part of the complete build process: uploading a bundle,
265-- docs and a distro to hackage.
266finallyUpload :: Settings -> Manager -> IO ()
267finallyUpload settings@Settings{..} man = do
268 putStrLn "Uploading bundle to Stackage Server"
270 mtoken <- lookupEnv "STACKAGE_AUTH_TOKEN"
273 Nothing -> decodeUtf8 <$> readFile "/auth-token"
274 Just token -> return $ pack token
277 let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
278 (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
279 { ubContents = serverBundle now (title ghcVer) slug plan
280 , ubAuthToken = token
282 putStrLn $ "New ident: " ++ unSnapshotIdent ident
284 putStrLn $ "Track progress at: " ++ loc
286 postBuild `catchAny` print
288 putStrLn "Uploading docs to Stackage Server"
289 res1 <- uploadDocs UploadDocs
291 , udAuthToken = token
292 , udDocs = pbDocDir pb
295 putStrLn $ "Doc upload response: " ++ tshow res1
297 ecreds <- tryIO $ readFile "/hackage-creds"
298 case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
299 [username, password] -> do
300 putStrLn "Uploading as Hackage distro"
301 res2 <- uploadHackageDistroNamed distroName plan username password man
302 putStrLn $ "Distro upload response: " ++ tshow res2
303 _ -> putStrLn "No creds found, skipping Hackage distro upload"
305 putStrLn "Uploading doc map"
306 uploadDocMap UploadDocMap
308 , udmAuthToken = token
309 , udmSnapshot = ident
310 , udmDocDir = pbDocDir pb
314 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