on e404fd2 help sign in
stackage/Stackage/InstallBuild.hs
100 lines 3.7 kB history raw
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE NoImplicitPrelude #-}
3{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6module Stackage.InstallBuild
7 ( InstallFlags (..)
8 , BuildPlanSource (..)
9 , installBuild
10 ) where
12import qualified Codec.Archive.Tar as Tar
13import qualified Codec.Compression.GZip as GZip
14import qualified Data.Yaml as Yaml
15import Network.HTTP.Client
16import Network.HTTP.Client.TLS (tlsManagerSettings)
17import Stackage.BuildPlan
18import Stackage.CheckBuildPlan
19import Stackage.PerformBuild
20import Stackage.Prelude
21import System.IO (BufferMode (LineBuffering), hSetBuffering)
23-- | Flags passed in from the command line.
24data InstallFlags = InstallFlags
25 { ifPlanSource :: !BuildPlanSource
26 , ifInstallDest :: !FilePath
27 , ifLogDir :: !(Maybe FilePath)
28 , ifJobs :: !Int
29 , ifGlobalInstall :: !Bool
30 , ifEnableTests :: !Bool
31 , ifEnableHaddock :: !Bool
32 , ifEnableLibProfiling :: !Bool
33 , ifEnableExecDyn :: !Bool
34 , ifVerbose :: !Bool
35 , ifSkipCheck :: !Bool
36 } deriving (Show)
38-- | Source for build plan.
39data BuildPlanSource = BPSBundleWeb String
40 | BPSFile FilePath
41 deriving (Show)
43getPerformBuild :: BuildPlan -> InstallFlags -> PerformBuild
44getPerformBuild plan InstallFlags{..} =
45 PerformBuild
46 { pbPlan = plan
47 , pbInstallDest = ifInstallDest
48 , pbLogDir = fromMaybe (ifInstallDest </> "logs") ifLogDir
49 , pbLog = hPut stdout
50 , pbJobs = ifJobs
51 , pbGlobalInstall = ifGlobalInstall
52 , pbEnableTests = ifEnableTests
53 , pbEnableHaddock = ifEnableHaddock
54 , pbEnableLibProfiling = ifEnableLibProfiling
55 , pbEnableExecDyn = ifEnableExecDyn
56 , pbVerbose = ifVerbose
57 , pbAllowNewer = ifSkipCheck
58 }
60-- | Install stackage from an existing build plan.
61installBuild :: InstallFlags -> IO ()
62installBuild installFlags@InstallFlags{..} = do
63 hSetBuffering stdout LineBuffering
65 putStrLn $ "Loading build plan"
66 plan <- case ifPlanSource of
67 BPSBundleWeb url -> withManager tlsManagerSettings $ \man -> do
68 req <- parseUrl url
69 res <- httpLbs req man
70 planBSL <- getPlanEntry $ Tar.read $ GZip.decompress (responseBody res)
71 decodeBuildPlan planBSL
72 BPSFile path -> Yaml.decodeFileEither (fpToString path) >>= either throwM return
74 if ifSkipCheck
75 then putStrLn "Skipping build plan check"
76 else do
77 putStrLn "Checking build plan"
78 checkBuildPlan plan
80 putStrLn "Performing build"
81 performBuild (getPerformBuild plan installFlags) >>= mapM_ putStrLn
83 where
84 getPlanEntry Tar.Done = throwIO NoBuildPlanException
85 getPlanEntry (Tar.Fail e) = throwIO e
86 getPlanEntry (Tar.Next entry entries)
87 | Tar.entryPath entry == "build-plan.yaml" =
88 case Tar.entryContent entry of
89 Tar.NormalFile bs _ -> return bs
90 _ -> throwIO NoBuildPlanException
91 | otherwise = getPlanEntry entries
93 decodeBuildPlan =
94 either throwIO return . Yaml.decodeEither' . toStrict
96data InstallBuildException = NoBuildPlanException
97 deriving (Typeable)
98instance Exception InstallBuildException
99instance Show InstallBuildException where
100 show NoBuildPlanException = "Bundle has missing or invalid build-plan.yaml"