ghcup-hs/app/ghcup-gen/Validate.hs

182 lines
5.5 KiB
Haskell
Raw Normal View History

2020-02-28 23:33:32 +00:00
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE QuasiQuotes #-}
module Validate where
import GHCup
2020-03-05 17:02:59 +00:00
import GHCup.Download
2020-02-28 23:33:32 +00:00
import GHCup.Types
2020-03-05 17:02:59 +00:00
import GHCup.Utils.Logger
2020-02-28 23:33:32 +00:00
import Control.Exception.Safe
2020-03-05 17:02:59 +00:00
import Control.Monad
2020-02-28 23:33:32 +00:00
import Control.Monad.IO.Class
2020-03-05 17:02:59 +00:00
import Control.Monad.Logger
import Control.Monad.Reader.Class
2020-02-28 23:33:32 +00:00
import Control.Monad.Trans.Class ( lift )
2020-02-29 23:07:39 +00:00
import Control.Monad.Trans.Reader ( runReaderT )
2020-03-05 17:02:59 +00:00
import Control.Monad.Trans.Resource ( runResourceT
, MonadUnliftIO
)
import Data.IORef
2020-02-28 23:33:32 +00:00
import Data.List
import Data.String.Interpolate
import Data.Versions
2020-03-05 17:02:59 +00:00
import Haskus.Utils.Variant.Excepts
import Optics
2020-02-28 23:33:32 +00:00
import System.Exit
2020-03-05 17:02:59 +00:00
import System.IO
2020-02-28 23:33:32 +00:00
2020-03-05 17:02:59 +00:00
import qualified Data.ByteString as B
2020-02-28 23:33:32 +00:00
import qualified Data.Map.Strict as M
data ValidationError = InternalError String
deriving Show
instance Exception ValidationError
2020-03-05 17:02:59 +00:00
addError :: (MonadReader (IORef Int) m, MonadIO m, Monad m) => m ()
addError = do
ref <- ask
liftIO $ modifyIORef ref (+ 1)
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
2020-03-03 00:59:19 +00:00
=> GHCupDownloads
2020-02-28 23:33:32 +00:00
-> m ExitCode
2020-03-08 17:30:08 +00:00
validate dls = do
2020-02-28 23:33:32 +00:00
ref <- liftIO $ newIORef 0
2020-03-03 00:59:19 +00:00
-- * verify binary downloads * --
2020-02-28 23:33:32 +00:00
flip runReaderT ref $ do
-- unique tags
2020-03-08 17:30:08 +00:00
forM_ (M.toList dls) $ \(t, _) -> checkUniqueTags t
2020-02-28 23:33:32 +00:00
-- required platforms
2020-03-08 17:30:08 +00:00
forM_ (M.toList dls) $ \(t, versions) ->
2020-02-28 23:33:32 +00:00
forM_ (M.toList versions) $ \(v, vi) ->
forM_ (M.toList $ _viArch vi) $ \(arch, pspecs) -> do
checkHasRequiredPlatforms t v arch (M.keys pspecs)
2020-03-05 17:02:59 +00:00
checkGHCisSemver
2020-03-08 17:30:08 +00:00
forM_ (M.toList dls) $ \(t, _) -> checkMandatoryTags t
2020-03-03 00:59:19 +00:00
2020-02-28 23:33:32 +00:00
-- exit
e <- liftIO $ readIORef ref
2020-03-05 17:02:59 +00:00
if e > 0
then pure $ ExitFailure e
else do
lift $ $(logInfo) [i|All good|]
pure ExitSuccess
2020-02-28 23:33:32 +00:00
where
checkHasRequiredPlatforms t v arch pspecs = do
let v' = prettyVer v
when (not $ any (== Linux UnknownLinux) pspecs) $ do
lift $ $(logError)
[i|Linux UnknownLinux missing for for #{t} #{v'} #{arch}|]
addError
2020-03-05 17:02:59 +00:00
when ((not $ any (== Darwin) pspecs) && arch == A_64) $ do
2020-02-28 23:33:32 +00:00
lift $ $(logError) [i|Darwin missing for #{t} #{v'} #{arch}|]
addError
2020-03-05 17:02:59 +00:00
when ((not $ any (== FreeBSD) pspecs) && arch == A_64) $ lift $ $(logWarn)
2020-02-28 23:33:32 +00:00
[i|FreeBSD missing for #{t} #{v'} #{arch}|]
checkUniqueTags tool = do
2020-03-08 17:30:08 +00:00
let allTags = join $ fmap snd $ availableToolVersions dls tool
2020-02-28 23:33:32 +00:00
let nonUnique =
fmap fst
. filter (\(_, b) -> not b)
<$> ( mapM
(\case
[] -> throwM $ InternalError "empty inner list"
(t : ts) ->
pure $ (t, ) $ if isUniqueTag t then ts == [] else True
)
. group
. sort
$ allTags
)
case join nonUnique of
[] -> pure ()
xs -> do
2020-03-05 17:02:59 +00:00
lift $ $(logError) [i|Tags not unique for #{tool}: #{xs}|]
2020-02-28 23:33:32 +00:00
addError
where
isUniqueTag Latest = True
isUniqueTag Recommended = True
2020-03-05 17:02:59 +00:00
checkGHCisSemver = do
2020-03-08 17:30:08 +00:00
let ghcVers = toListOf (ix GHC % to M.keys % folded) dls
2020-03-05 17:02:59 +00:00
forM_ ghcVers $ \v -> case semver (prettyVer v) of
Left _ -> do
lift $ $(logError) [i|GHC version #{v} is not valid semver|]
addError
Right _ -> pure ()
2020-02-28 23:33:32 +00:00
2020-03-05 17:02:59 +00:00
-- a tool must have at least one of each mandatory tags
checkMandatoryTags tool = do
2020-03-08 17:30:08 +00:00
let allTags = join $ fmap snd $ availableToolVersions dls tool
2020-03-05 17:02:59 +00:00
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
False -> do
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
addError
True -> pure ()
validateTarballs :: ( Monad m
, MonadLogger m
, MonadThrow m
, MonadIO m
, MonadUnliftIO m
2020-03-08 17:30:08 +00:00
, MonadMask m
2020-03-05 17:02:59 +00:00
)
=> GHCupDownloads
-> m ExitCode
2020-03-08 17:30:08 +00:00
validateTarballs dls = do
2020-03-05 17:02:59 +00:00
ref <- liftIO $ newIORef 0
flip runReaderT ref $ do
2020-03-08 17:30:08 +00:00
-- download/verify all binary tarballs
2020-03-05 17:02:59 +00:00
let
2020-03-08 17:30:08 +00:00
dlbis = nub $ join $ (M.elems dls) <&> \versions ->
2020-03-05 17:02:59 +00:00
join $ (M.elems versions) <&> \vi ->
join $ (M.elems $ _viArch vi) <&> \pspecs ->
join $ (M.elems pspecs) <&> \pverspecs -> (M.elems pverspecs)
2020-03-08 17:30:08 +00:00
forM_ dlbis $ downloadAll
let dlsrc = nub $ join $ (M.elems dls) <&> \versions ->
join $ (M.elems versions) <&> maybe [] (: []) . _viSourceDL
forM_ dlsrc $ downloadAll
2020-03-05 17:02:59 +00:00
-- exit
e <- liftIO $ readIORef ref
if e > 0
then pure $ ExitFailure e
else do
lift $ $(logInfo) [i|All good|]
pure ExitSuccess
where
downloadAll dli = do
let settings = Settings True GHCupURL False
let runLogger = myLoggerT LoggerConfig { lcPrintDebug = True
, colorOutter = B.hPut stderr
, rawOutter = (\_ -> pure ())
}
r <-
runLogger
. flip runReaderT settings
. runResourceT
. runE
$ downloadCached dli Nothing
case r of
VRight _ -> pure ()
VLeft e -> do
lift $ $(logError)
[i|Could not download (or verify hash) of #{dli}, Error was: #{e}|]
addError