ghcup-hs/lib/GHCup.hs

687 lines
22 KiB
Haskell
Raw Permalink Normal View History

2020-01-14 21:55:34 +00:00
{-# LANGUAGE DataKinds #-}
2020-02-19 19:54:23 +00:00
{-# LANGUAGE DeriveGeneric #-}
2020-01-14 21:55:34 +00:00
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
2020-02-19 19:54:23 +00:00
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes #-}
2020-01-14 21:55:34 +00:00
{-# LANGUAGE TemplateHaskell #-}
2020-02-19 19:54:23 +00:00
{-# LANGUAGE TypeFamilies #-}
2020-02-24 13:56:13 +00:00
{-# LANGUAGE TypeApplications #-}
2020-01-14 21:55:34 +00:00
module GHCup where
2020-01-16 22:27:38 +00:00
2020-03-03 00:59:19 +00:00
import GHCup.Download
import GHCup.Errors
import GHCup.Platform
2020-03-01 00:05:02 +00:00
import GHCup.Types
import GHCup.Types.JSON ( )
2020-03-03 00:59:19 +00:00
import GHCup.Types.Optics
import GHCup.Utils
import GHCup.Utils.File
import GHCup.Utils.Prelude
2020-03-05 17:02:59 +00:00
import GHCup.Utils.String.QQ
import GHCup.Utils.Version.QQ
2020-03-08 17:30:08 +00:00
import GHCup.Version
2020-03-01 00:05:02 +00:00
2020-01-14 21:55:34 +00:00
import Control.Applicative
2020-03-01 00:05:02 +00:00
import Control.Exception.Safe
2020-01-16 22:27:38 +00:00
import Control.Monad
2020-02-24 13:56:13 +00:00
import Control.Monad.Fail ( MonadFail )
2020-02-22 18:21:10 +00:00
import Control.Monad.Logger
2020-03-01 00:05:02 +00:00
import Control.Monad.Reader
2020-02-22 18:21:10 +00:00
import Control.Monad.Trans.Class ( lift )
2020-03-01 01:21:40 +00:00
import Control.Monad.Trans.Resource
hiding ( throwM )
2020-02-18 08:40:01 +00:00
import Data.ByteString ( ByteString )
2020-03-01 00:05:02 +00:00
import Data.List
import Data.Maybe
import Data.String.Interpolate
2020-01-16 22:27:38 +00:00
import Data.Versions
2020-03-01 00:05:02 +00:00
import Data.Word8
import GHC.IO.Exception
2020-01-14 21:55:34 +00:00
import HPath
import HPath.IO
2020-03-01 00:05:02 +00:00
import Haskus.Utils.Variant.Excepts
2020-01-14 21:55:34 +00:00
import Optics
import Prelude hiding ( abs
2020-01-16 22:27:38 +00:00
, readFile
2020-03-03 00:59:19 +00:00
, writeFile
2020-01-14 21:55:34 +00:00
)
2020-01-17 22:29:16 +00:00
import System.IO.Error
2020-03-03 00:59:19 +00:00
import System.Posix.FilePath ( getSearchPath )
2020-03-01 00:05:02 +00:00
import System.Posix.RawFilePath.Directory.Errors
( hideError )
2020-03-03 00:59:19 +00:00
2020-03-01 00:05:02 +00:00
import qualified Data.ByteString as B
import qualified Data.Map.Strict as Map
import qualified Data.Text.Encoding as E
2020-02-22 18:21:10 +00:00
-------------------------
--[ Tool installation ]--
-------------------------
2020-02-24 13:56:13 +00:00
2020-03-08 17:30:08 +00:00
installGHCBin :: ( MonadFail m
, MonadMask m
, MonadCatch m
, MonadReader Settings m
, MonadLogger m
, MonadResource m
, MonadIO m
)
=> GHCupDownloads
-> Version
-> Maybe PlatformRequest -- ^ if Nothing, looks up current host platform
-> Excepts
'[ AlreadyInstalled
, BuildFailed
, DigestError
, DistroNotFound
, DownloadFailed
, NoCompatibleArch
, NoCompatiblePlatform
, NoDownload
, NotInstalled
, UnknownArchive
]
m
()
installGHCBin bDls ver mpfReq = do
lift $ $(logDebug) [i|Requested to install GHC with #{ver}|]
whenM (liftIO $ toolAlreadyInstalled GHC ver)
$ (throwE $ AlreadyInstalled GHC ver)
2020-02-24 13:56:13 +00:00
Settings {..} <- lift ask
-- download (or use cached version)
2020-03-08 17:30:08 +00:00
dlinfo <- liftE $ getDownloadInfo bDls GHC ver mpfReq
2020-03-03 00:59:19 +00:00
dl <- liftE $ downloadCached dlinfo Nothing
2020-02-24 13:56:13 +00:00
-- unpack
2020-03-08 17:30:08 +00:00
tmpUnpack <- lift mkGhcupTmpDir
2020-03-03 00:59:19 +00:00
liftE $ unpackToDir tmpUnpack dl
2020-02-24 13:56:13 +00:00
-- prepare paths
2020-03-08 17:30:08 +00:00
ghcdir <- liftIO $ ghcupGHCDir ver
2020-02-22 18:21:10 +00:00
-- the subdir of the archive where we do the work
2020-03-03 00:59:19 +00:00
let archiveSubdir = maybe tmpUnpack (tmpUnpack </>) (view dlSubdir dlinfo)
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
catchAllE
(\es ->
liftIO (hideError doesNotExistErrorType $ deleteDirRecursive ghcdir)
>> throwE (BuildFailed archiveSubdir es)
)
$ installGHC' archiveSubdir ghcdir
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
-- only clean up dir if the build succeeded
liftIO $ deleteDirRecursive tmpUnpack
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
liftE $ postGHCInstall ver
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
where
-- | Install an unpacked GHC distribution. This only deals with the GHC build system and nothing else.
installGHC' :: (MonadLogger m, MonadIO m)
=> Path Abs -- ^ Path to the unpacked GHC bindist (where the configure script resides)
-> Path Abs -- ^ Path to install to
-> Excepts '[ProcessError] m ()
installGHC' path inst = do
lift $ $(logInfo) [s|Installing GHC (this may take a while)|]
lEM $ liftIO $ execLogged [s|./configure|]
False
[[s|--prefix=|] <> toFilePath inst]
([rel|ghc-configure.log|] :: Path Rel)
(Just path)
Nothing
lEM $ liftIO $ execLogged [s|make|]
True
[[s|install|]]
([rel|ghc-make.log|] :: Path Rel)
(Just path)
Nothing
pure ()
installCabalBin :: ( MonadMask m
, MonadCatch m
, MonadReader Settings m
, MonadLogger m
, MonadResource m
, MonadIO m
)
=> GHCupDownloads
-> Version
-> Maybe PlatformRequest -- ^ if Nothing, looks up current host platform
-> Excepts
'[ CopyError
, DigestError
, DistroNotFound
, DownloadFailed
, NoCompatibleArch
, NoCompatiblePlatform
, NoDownload
, UnknownArchive
]
m
()
installCabalBin bDls ver mpfReq = do
lift $ $(logDebug) [i|Requested to install cabal version #{ver}|]
Settings {..} <- lift ask
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
-- download (or use cached version)
dlinfo <- liftE $ getDownloadInfo bDls Cabal ver mpfReq
dl <- liftE $ downloadCached dlinfo Nothing
-- unpack
tmpUnpack <- lift withGHCupTmpDir
liftE $ unpackToDir tmpUnpack dl
-- prepare paths
bindir <- liftIO ghcupBinDir
-- the subdir of the archive where we do the work
let archiveSubdir = maybe tmpUnpack (tmpUnpack </>) (view dlSubdir dlinfo)
liftE $ installCabal' archiveSubdir bindir
pure ()
where
-- | Install an unpacked cabal distribution.
installCabal' :: (MonadLogger m, MonadCatch m, MonadIO m)
=> Path Abs -- ^ Path to the unpacked cabal bindist (where the executable resides)
-> Path Abs -- ^ Path to install to
-> Excepts '[CopyError] m ()
installCabal' path inst = do
lift $ $(logInfo) [s|Installing cabal|]
let cabalFile = [rel|cabal|] :: Path Rel
liftIO $ createDirIfMissing newDirPerms inst
handleIO (throwE . CopyError . show) $ liftIO $ copyFile
(path </> cabalFile)
(inst </> cabalFile)
Overwrite
2020-02-22 18:21:10 +00:00
2020-02-18 08:40:01 +00:00
2020-02-28 23:33:32 +00:00
---------------
--[ Set GHC ]--
---------------
2020-02-24 13:56:13 +00:00
-- | Set GHC symlinks in ~/.ghcup/bin for the requested GHC version. The behavior depends
-- on `SetGHC`:
--
2020-02-28 23:33:32 +00:00
-- * SetGHCOnly: ~/.ghcup/bin/ghc -> ~/.ghcup/ghc/<ver>/bin/ghc
2020-03-08 22:54:41 +00:00
-- * SetGHC_XY: ~/.ghcup/bin/ghc-X.Y -> ~/.ghcup/ghc/<ver>/bin/ghc
-- * SetGHC_XYZ: ~/.ghcup/bin/ghc-<ver> -> ~/.ghcup/ghc/<ver>/bin/ghc
2020-02-24 13:56:13 +00:00
--
-- Additionally creates a ~/.ghcup/share -> ~/.ghcup/ghc/<ver>/share symlink
-- for `SetGHCOnly` constructor.
2020-03-08 17:30:08 +00:00
setGHC :: (MonadLogger m, MonadThrow m, MonadFail m, MonadIO m)
2020-02-24 13:56:13 +00:00
=> Version
-> SetGHC
-> Excepts '[NotInstalled] m ()
setGHC ver sghc = do
2020-02-28 23:33:32 +00:00
let verBS = verToBS ver
2020-03-03 00:59:19 +00:00
ghcdir <- liftIO $ ghcupGHCDir ver
2020-02-24 13:56:13 +00:00
-- symlink destination
2020-03-03 00:59:19 +00:00
bindir <- liftIO $ ghcupBinDir
liftIO $ hideError AlreadyExists $ createDirRecursive newDirPerms bindir
2020-03-08 17:30:08 +00:00
-- first delete the old symlinks (this fixes compatibility issues
-- with old ghcup)
case sghc of
2020-03-08 22:54:41 +00:00
SetGHCOnly -> liftE $ rmPlain ver
SetGHC_XY -> lift $ rmMajorSymlinks ver
SetGHC_XYZ -> lift $ rmMinorSymlinks ver
2020-02-24 13:56:13 +00:00
-- for ghc tools (ghc, ghci, haddock, ...)
2020-02-28 23:33:32 +00:00
verfiles <- ghcToolFiles ver
2020-02-29 23:07:39 +00:00
forM_ verfiles $ \file -> do
2020-03-03 00:59:19 +00:00
liftIO $ hideError doesNotExistErrorType $ deleteFile (bindir </> file)
2020-02-24 13:56:13 +00:00
targetFile <- case sghc of
2020-03-08 22:54:41 +00:00
SetGHCOnly -> pure file
SetGHC_XY -> do
2020-02-29 23:07:39 +00:00
major' <-
2020-02-28 23:33:32 +00:00
(\(mj, mi) -> E.encodeUtf8 $ intToText mj <> [s|.|] <> intToText mi)
<$> getGHCMajor ver
2020-02-29 23:07:39 +00:00
parseRel (toFilePath file <> B.singleton _hyphen <> major')
2020-03-08 22:54:41 +00:00
SetGHC_XYZ -> parseRel (toFilePath file <> B.singleton _hyphen <> verBS)
2020-03-08 17:30:08 +00:00
-- create symlink
let fullF = bindir </> targetFile
let destL = ghcLinkDestination (toFilePath file) ver
lift $ $(logDebug) [i|ln -s #{destL} #{toFilePath fullF}|]
liftIO $ createSymlink fullF destL
2020-02-24 13:56:13 +00:00
-- create symlink for share dir
2020-03-08 17:30:08 +00:00
lift $ symlinkShareDir ghcdir verBS
2020-02-24 13:56:13 +00:00
pure ()
where
2020-02-28 23:33:32 +00:00
2020-03-08 17:30:08 +00:00
symlinkShareDir :: (MonadIO m, MonadLogger m)
=> Path Abs
-> ByteString
-> m ()
2020-02-28 23:33:32 +00:00
symlinkShareDir ghcdir verBS = do
2020-03-08 17:30:08 +00:00
destdir <- liftIO $ ghcupBaseDir
2020-02-28 23:33:32 +00:00
case sghc of
SetGHCOnly -> do
let sharedir = [rel|share|] :: Path Rel
let fullsharedir = ghcdir </> sharedir
2020-03-08 17:30:08 +00:00
whenM (liftIO $ doesDirectoryExist fullsharedir) $ do
let fullF = destdir </> sharedir
let targetF = [s|./ghc/|] <> verBS <> [s|/|] <> toFilePath sharedir
$(logDebug) [i|rm -f #{fullF}|]
liftIO $ hideError doesNotExistErrorType $ deleteFile fullF
$(logDebug) [i|ln -s #{targetF} #{fullF}|]
liftIO $ createSymlink fullF targetF
2020-02-28 23:33:32 +00:00
_ -> pure ()
------------------
--[ List tools ]--
------------------
data ListCriteria = ListInstalled
| ListSet
deriving Show
data ListResult = ListResult
{ lTool :: Tool
, lVer :: Version
, lTag :: [Tag]
, lInstalled :: Bool
, lSet :: Bool
2020-03-08 17:30:08 +00:00
, fromSrc :: Bool
2020-02-28 23:33:32 +00:00
}
deriving Show
2020-03-08 17:30:08 +00:00
availableToolVersions :: GHCupDownloads -> Tool -> [(Version, [Tag])]
2020-02-28 23:33:32 +00:00
availableToolVersions av tool = toListOf
(ix tool % to (fmap (\(v, vi) -> (v, (_viTags vi))) . Map.toList) % folded)
av
2020-03-08 17:30:08 +00:00
listVersions :: GHCupDownloads
2020-03-03 00:59:19 +00:00
-> Maybe Tool
2020-02-28 23:33:32 +00:00
-> Maybe ListCriteria
2020-03-03 00:59:19 +00:00
-> IO [ListResult]
listVersions av lt criteria = case lt of
2020-02-28 23:33:32 +00:00
Just t -> do
filter' <$> forM (availableToolVersions av t) (toListResult t)
Nothing -> do
2020-03-03 00:59:19 +00:00
ghcvers <- listVersions av (Just GHC) criteria
cabalvers <- listVersions av (Just Cabal) criteria
2020-03-08 17:30:08 +00:00
ghcupvers <- listVersions av (Just GHCup) criteria
pure (ghcvers <> cabalvers <> ghcupvers)
2020-02-28 23:33:32 +00:00
where
toListResult :: Tool -> (Version, [Tag]) -> IO ListResult
toListResult t (v, tags) = case t of
GHC -> do
lSet <- fmap (maybe False (== v)) $ ghcSet
lInstalled <- ghcInstalled v
2020-03-08 17:30:08 +00:00
fromSrc <- ghcSrcInstalled v
2020-02-28 23:33:32 +00:00
pure ListResult { lVer = v, lTag = tags, lTool = t, .. }
Cabal -> do
lSet <- fmap (== v) $ cabalSet
lInstalled <- cabalInstalled v
2020-03-08 17:30:08 +00:00
pure ListResult { lVer = v, lTag = tags, lTool = t, fromSrc = False, .. }
GHCup -> do
let lSet = prettyPVP ghcUpVer == prettyVer v
let lInstalled = True
pure ListResult { lVer = v, lTag = tags, lTool = t, fromSrc = False, .. }
2020-02-28 23:33:32 +00:00
filter' :: [ListResult] -> [ListResult]
filter' lr = case criteria of
Nothing -> lr
Just ListInstalled -> filter (\ListResult {..} -> lInstalled) lr
Just ListSet -> filter (\ListResult {..} -> lSet) lr
2020-02-29 23:07:39 +00:00
--------------
--[ GHC rm ]--
--------------
2020-02-28 23:33:32 +00:00
-- | This function may throw and crash in various ways.
rmGHCVer :: (MonadThrow m, MonadLogger m, MonadIO m, MonadFail m)
=> Version
-> Excepts '[NotInstalled] m ()
rmGHCVer ver = do
isSetGHC <- fmap (maybe False (== ver)) $ ghcSet
dir <- liftIO $ ghcupGHCDir ver
let d' = toFilePath dir
2020-03-08 17:30:08 +00:00
exists <- liftIO $ doesDirectoryExist dir
2020-02-28 23:33:32 +00:00
if exists
then do
2020-02-29 23:07:39 +00:00
-- this isn't atomic, order matters
2020-02-28 23:33:32 +00:00
lift $ $(logInfo) [i|Removing directory recursively: #{d'}|]
liftIO $ deleteDirRecursive dir
lift $ $(logInfo) [i|Removing ghc-x.y.z symlinks|]
2020-03-08 17:30:08 +00:00
lift $ rmMinorSymlinks ver
2020-02-28 23:33:32 +00:00
2020-03-01 01:21:40 +00:00
lift $ $(logInfo) [i|Removing/rewiring ghc-x.y symlinks|]
2020-03-08 17:30:08 +00:00
-- first remove
lift $ rmMajorSymlinks ver
-- then fix them (e.g. with an earlier version)
(mj, mi) <- getGHCMajor ver
2020-03-08 22:54:41 +00:00
getGHCForMajor mj mi >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY)
2020-03-08 17:30:08 +00:00
2020-02-28 23:33:32 +00:00
2020-03-08 17:30:08 +00:00
when isSetGHC $ do
2020-02-28 23:33:32 +00:00
lift $ $(logInfo) [i|Removing ghc symlinks|]
2020-03-08 17:30:08 +00:00
liftE $ rmPlain ver
2020-02-28 23:33:32 +00:00
liftIO
$ ghcupBaseDir
>>= hideError doesNotExistErrorType
. deleteFile
. (</> ([rel|share|] :: Path Rel))
2020-03-08 17:30:08 +00:00
else throwE (NotInstalled GHC ver)
2020-02-28 23:33:32 +00:00
2020-02-24 13:56:13 +00:00
2020-02-29 23:07:39 +00:00
------------------
--[ Debug info ]--
------------------
getDebugInfo :: (MonadLogger m, MonadCatch m, MonadReader Settings m, MonadIO m)
=> Excepts
2020-03-08 17:30:08 +00:00
'[NoCompatiblePlatform , NoCompatibleArch , DistroNotFound]
2020-02-29 23:07:39 +00:00
m
DebugInfo
getDebugInfo = do
diBaseDir <- liftIO $ ghcupBaseDir
diBinDir <- liftIO $ ghcupBinDir
diGHCDir <- liftIO $ ghcupGHCBaseDir
diCacheDir <- liftIO $ ghcupCacheDir
diURLSource <- lift $ getUrlSource
diArch <- lE getArchitecture
diPlatform <- liftE $ getPlatform
pure $ DebugInfo { .. }
2020-02-18 08:40:01 +00:00
2020-03-05 17:02:59 +00:00
2020-03-03 00:59:19 +00:00
---------------
--[ Compile ]--
---------------
2020-02-22 18:21:10 +00:00
2020-03-08 17:30:08 +00:00
compileGHC :: ( MonadMask m
, MonadReader Settings m
2020-03-03 00:59:19 +00:00
, MonadThrow m
, MonadResource m
, MonadLogger m
, MonadIO m
, MonadFail m
)
2020-03-08 17:30:08 +00:00
=> GHCupDownloads
2020-03-03 00:59:19 +00:00
-> Version -- ^ version to install
-> Version -- ^ version to bootstrap with
-> Maybe Int -- ^ jobs
-> Maybe (Path Abs) -- ^ build config
-> Excepts
'[ AlreadyInstalled
2020-03-08 17:30:08 +00:00
, BuildFailed
2020-03-03 00:59:19 +00:00
, DigestError
2020-03-08 17:30:08 +00:00
, DownloadFailed
, GHCupSetError
, NoDownload
, UnknownArchive
2020-03-03 00:59:19 +00:00
]
m
()
compileGHC dls tver bver jobs mbuildConfig = do
lift $ $(logDebug) [i|Requested to compile: #{tver} with #{bver}|]
2020-03-08 17:30:08 +00:00
whenM (liftIO $ toolAlreadyInstalled GHC tver)
(throwE $ AlreadyInstalled GHC tver)
2020-02-24 13:56:13 +00:00
2020-03-03 00:59:19 +00:00
-- download source tarball
2020-03-08 17:30:08 +00:00
dlInfo <- preview (ix GHC % ix tver % viSourceDL % _Just) dls ?? NoDownload
2020-03-03 00:59:19 +00:00
dl <- liftE $ downloadCached dlInfo Nothing
2020-02-24 13:56:13 +00:00
2020-03-03 00:59:19 +00:00
-- unpack
tmpUnpack <- lift mkGhcupTmpDir
liftE $ unpackToDir tmpUnpack dl
2020-02-28 23:33:32 +00:00
2020-03-03 00:59:19 +00:00
bghc <- parseRel ([s|ghc-|] <> verToBS bver)
let workdir = maybe id (flip (</>)) (view dlSubdir dlInfo) $ tmpUnpack
ghcdir <- liftIO $ ghcupGHCDir tver
2020-03-08 17:30:08 +00:00
catchAllE
(\es ->
liftIO (hideError doesNotExistErrorType $ deleteDirRecursive ghcdir)
>> throwE (BuildFailed workdir es)
)
$ compile bghc ghcdir workdir
markSrcBuilt ghcdir workdir
-- only clean up dir if the build succeeded
liftIO $ deleteDirRecursive tmpUnpack
reThrowAll GHCupSetError $ postGHCInstall tver
2020-03-03 00:59:19 +00:00
pure ()
2020-02-28 23:33:32 +00:00
where
2020-03-03 00:59:19 +00:00
defaultConf = [s|
V=0
BUILD_MAN = NO
BUILD_SPHINX_HTML = NO
BUILD_SPHINX_PDF = NO
HADDOCK_DOCS = YES
GhcWithLlvmCodeGen = YES|]
2020-03-08 17:30:08 +00:00
compile :: (MonadCatch m, MonadLogger m, MonadIO m)
=> Path Rel
-> Path Abs
-> Path Abs
-> Excepts
'[NoDownload , FileDoesNotExistError , ProcessError]
m
()
compile bghc ghcdir workdir = do
lift $ $(logInfo) [i|configuring build|]
if
| tver >= [vver|8.8.0|] -> do
spaths <- catMaybes . fmap parseAbs <$> liftIO getSearchPath
bghcPath <- (liftIO $ searchPath spaths bghc) !? NoDownload
newEnv <- addToCurrentEnv [([s|GHC|], toFilePath bghcPath)]
lEM $ liftIO $ execLogged [s|./configure|]
False
[[s|--prefix=|] <> toFilePath ghcdir]
([rel|ghc-configure.log|] :: Path Rel)
(Just workdir)
(Just newEnv)
| otherwise -> do
lEM $ liftIO $ execLogged
[s|./configure|]
False
[ [s|--prefix=|] <> toFilePath ghcdir
, [s|--with-ghc=|] <> toFilePath bghc
]
([rel|ghc-configure.log|] :: Path Rel)
(Just workdir)
Nothing
case mbuildConfig of
Just bc -> liftIOException
doesNotExistErrorType
(FileDoesNotExistError $ toFilePath bc)
(liftIO $ copyFile bc (build_mk workdir) Overwrite)
Nothing ->
liftIO $ writeFile (build_mk workdir) (Just newFilePerms) defaultConf
lift
$ $(logInfo)
[i|Building (this may take a while)... Run 'tail -f ~/.ghcup/logs/ghc-make.log' to see the progress.|]
lEM $ liftIO $ execLogged [s|make|]
True
(maybe [] (\j -> [[s|-j|] <> fS (show j)]) jobs)
([rel|ghc-make.log|] :: Path Rel)
(Just workdir)
Nothing
lift $ $(logInfo) [i|Installing...|]
lEM $ liftIO $ execLogged [s|make|]
True
[[s|install|]]
([rel|ghc-make.log|] :: Path Rel)
(Just workdir)
Nothing
markSrcBuilt ghcdir workdir = do
let dest = (ghcdir </> ghcUpSrcBuiltFile)
liftIO $ copyFile (build_mk workdir) dest Overwrite
build_mk workdir = workdir </> ([rel|mk/build.mk|] :: Path Rel)
compileCabal :: ( MonadReader Settings m
, MonadResource m
, MonadMask m
, MonadLogger m
, MonadIO m
)
=> GHCupDownloads
-> Version -- ^ version to install
-> Version -- ^ GHC version to build with
-> Maybe Int
-> Excepts
'[ BuildFailed
, DigestError
, DownloadFailed
, NoDownload
, UnknownArchive
]
m
()
compileCabal dls tver bver jobs = do
lift $ $(logDebug) [i|Requested to compile: #{tver} with ghc-#{bver}|]
2020-03-03 00:59:19 +00:00
2020-03-08 17:30:08 +00:00
-- download source tarball
dlInfo <- preview (ix Cabal % ix tver % viSourceDL % _Just) dls ?? NoDownload
dl <- liftE $ downloadCached dlInfo Nothing
2020-03-03 00:59:19 +00:00
2020-03-08 17:30:08 +00:00
-- unpack
tmpUnpack <- lift mkGhcupTmpDir
liftE $ unpackToDir tmpUnpack dl
let workdir = maybe id (flip (</>)) (view dlSubdir dlInfo) $ tmpUnpack
reThrowAll (BuildFailed workdir) $ compile workdir
-- only clean up dir if the build succeeded
liftIO $ deleteDirRecursive tmpUnpack
pure ()
where
compile :: (MonadLogger m, MonadIO m)
=> Path Abs
-> Excepts '[ProcessError] m ()
compile workdir = do
lift
$ $(logInfo)
[i|Building (this may take a while)... Run 'tail -f ~/.ghcup/logs/cabal-bootstrap.log' to see the progress.|]
let v' = verToBS bver
cabal_bin <- liftIO $ ghcupBinDir
newEnv <- lift $ addToCurrentEnv
[ ([s|GHC|] , [s|ghc-|] <> v')
, ([s|GHC_PKG|], [s|ghc-pkg-|] <> v')
, ([s|GHC_VER|], v')
, ([s|PREFIX|] , toFilePath cabal_bin)
]
lEM $ liftIO $ execLogged [s|./bootstrap.sh|]
False
(maybe [] (\j -> [[s|-j|], fS (show j)]) jobs)
([rel|cabal-bootstrap.log|] :: Path Rel)
(Just workdir)
(Just newEnv)
---------------------
--[ Upgrade GHCup ]--
---------------------
2020-03-03 22:34:25 +00:00
2020-03-08 17:30:08 +00:00
upgradeGHCup :: ( MonadMask m
, MonadReader Settings m
2020-03-03 22:34:25 +00:00
, MonadCatch m
, MonadLogger m
, MonadThrow m
, MonadResource m
, MonadIO m
)
2020-03-08 17:30:08 +00:00
=> GHCupDownloads
2020-03-03 22:34:25 +00:00
-> Maybe (Path Abs) -- ^ full file destination to write ghcup into
-> Excepts
2020-03-08 17:30:08 +00:00
'[ CopyError
, DigestError
2020-03-03 22:34:25 +00:00
, DistroNotFound
2020-03-08 17:30:08 +00:00
, DownloadFailed
2020-03-03 22:34:25 +00:00
, NoCompatibleArch
2020-03-08 17:30:08 +00:00
, NoCompatiblePlatform
2020-03-03 22:34:25 +00:00
, NoDownload
]
m
Version
upgradeGHCup dls mtarget = do
lift $ $(logInfo) [i|Upgrading GHCup...|]
let latestVer = head $ getTagged dls GHCup Latest
2020-03-08 17:30:08 +00:00
dli <- liftE $ getDownloadInfo dls GHCup latestVer Nothing
2020-03-03 22:34:25 +00:00
tmp <- lift withGHCupTmpDir
let fn = [rel|ghcup|] :: Path Rel
2020-03-05 17:02:59 +00:00
p <- liftE $ download dli tmp (Just fn)
2020-03-03 22:34:25 +00:00
case mtarget of
Nothing -> do
dest <- liftIO $ ghcupBinDir
2020-03-08 17:30:08 +00:00
handleIO (throwE . CopyError . show) $ liftIO $ copyFile p
(dest </> fn)
Overwrite
2020-03-03 22:34:25 +00:00
Just fullDest -> liftIO $ copyFile p fullDest Overwrite
pure latestVer
2020-03-03 00:59:19 +00:00
-------------
--[ Other ]--
-------------
2020-03-08 17:30:08 +00:00
-- | Creates ghc-x.y.z and ghc-x.y symlinks. This is used for
-- both installing from source and bindist.
postGHCInstall :: (MonadLogger m, MonadThrow m, MonadFail m, MonadIO m)
2020-03-03 00:59:19 +00:00
=> Version
-> Excepts '[NotInstalled] m ()
postGHCInstall ver = do
2020-03-08 22:54:41 +00:00
liftE $ setGHC ver SetGHC_XYZ
2020-02-28 23:33:32 +00:00
2020-03-03 00:59:19 +00:00
-- Create ghc-x.y symlinks. This may not be the current
-- version, create it regardless.
(mj, mi) <- liftIO $ getGHCMajor ver
2020-03-08 22:54:41 +00:00
getGHCForMajor mj mi >>= mapM_ (\v -> liftE $ setGHC v SetGHC_XY)