module Retrieve where import qualified Flatpak import qualified Cabal.Plan as Plan import qualified Network.HTTP.Client as Http import Network.HTTP.Client.TLS (tlsManagerSettings) import Network.HTTP.Types.Status (statusCode) import Control.Monad (when) import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.ByteString.Char8 as B import qualified Data.Text.Encoding as TextEnc import qualified Data.Text as Text import qualified Data.Map as Map import qualified Data.List.HT as ListHT import Data.Map (Map) import Data.Tuple.HT (mapFst) import Data.Bool.HT (if') import Text.Printf (printf) formatVersion :: Plan.Ver -> String formatVersion = Text.unpack . Plan.dispVer archGHC :: Flatpak.Arch -> String archGHC arch = case arch of Flatpak.I386 -> "i386" Flatpak.X86_64 -> "x86_64" Flatpak.ARM -> "armv7" Flatpak.AArch64 -> "aarch64" ghcDirUrl :: Plan.PkgId -> String ghcDirUrl (Plan.PkgId (Plan.PkgName compName) compVersion) = printf "https://downloads.haskell.org/%s/%s/" (Text.unpack compName) (formatVersion compVersion) {- | ghc-8.4.4-x86_64-deb9 is available but fails due to missing libnuma.so.1 -} ghcNameScheme :: Plan.Ver -> String ghcNameScheme ghcVer = if' (ghcVer >= Plan.Ver [8, 6,1]) "%s-%s-deb9-linux.tar.xz" $ if' (ghcVer >= Plan.Ver [7,10,3]) "%s-%s-deb8-linux.tar.xz" $ if' (ghcVer >= Plan.Ver [7, 8,1]) "%s-%s-unknown-linux-deb7.tar.xz" $ "%s-%s-unknown-linux.tar.bz2" ghcArchive :: Plan.PkgId -> Flatpak.Arch -> String ghcArchive compiler@(Plan.PkgId _ compVersion) arch = printf (ghcNameScheme compVersion) (Text.unpack $ Plan.dispPkgId compiler) (archGHC arch) httpsGet :: String -> IO BL.ByteString httpsGet url = do response <- do request <- Http.parseRequest url manager <- Http.newManager tlsManagerSettings Http.httpLbs request manager case statusCode $ Http.responseStatus response of 200 -> return $ Http.responseBody response code -> fail $ "HTTPS get failed with status code: " ++ show code ghcHashes :: Plan.PkgId -> IO (String, Map BL.ByteString BL.ByteString) ghcHashes compiler = do let sha256Url = ghcDirUrl compiler ++ "SHA256SUMS" ghcSha256s <- httpsGet sha256Url let (ghcSha256Map, ghcSha256Corrupts) = mapFst Map.fromList $ ListHT.partitionMaybe (\line -> case BL.words line of [hash,archive] -> Just (archive,hash) _ -> Nothing) (BL.lines ghcSha256s) when (not $ null ghcSha256Corrupts) $ fail $ unlines $ (printf "corrupt lines in %s:" sha256Url) : map BL.unpack ghcSha256Corrupts return (sha256Url,ghcSha256Map) ghcHash :: (String, Map BL.ByteString BL.ByteString) -> Plan.PkgId -> Flatpak.Arch -> Either String Plan.Sha256 ghcHash (sha256Url,ghcSha256Map) compiler arch = do let ghcName = ghcArchive compiler arch let maybeFail msg = maybe (Left msg) Right hashStr <- maybeFail (printf "could not find SHA256 checksum for %s in %s" ghcName sha256Url) $ Map.lookup (BL.pack $ "./"++ghcName) ghcSha256Map sha256 <- maybeFail ("could not parse SHA256 checksum " ++ BL.unpack hashStr) $ Plan.parseSha256 $ TextEnc.decodeLatin1 $ B.concat $ BL.toChunks hashStr return sha256