{-# LANGUAGE OverloadedStrings #-} module Language.ATS.Package.Dependency ( -- * Functions fetchDeps , buildHelper -- * Types , SetupScript ) where -- import Codec.Archive as Archive import qualified Codec.Archive.Tar as Tar import Codec.Archive.Zip (ZipOption (..), extractFilesFromArchive, toArchive) import qualified Codec.Compression.BZip as Bzip import qualified Codec.Compression.GZip as Gzip import qualified Codec.Compression.Lzma as Lzma import Control.Concurrent.ParallelIO.Global import qualified Data.ByteString.Lazy as BSL import qualified Data.Text.Lazy as TL import Development.Shake.ATS import Language.ATS.Package.Build.C import Language.ATS.Package.Compiler (SetupScript) import Language.ATS.Package.Config import Language.ATS.Package.Error import Language.ATS.Package.PackageSet import Language.ATS.Package.Type import Quaalude getTgt :: CCompiler -> Maybe String getTgt (GCC x _) = x getTgt (GHC x _) = x getTgt _ = Nothing fetchDeps :: Verbosity -- ^ Shake verbosity -> CCompiler -- ^ C compiler to use -> Maybe String -- ^ Args -> [IO ()] -- ^ Setup steps that can be performed concurrently -> [(String, ATSConstraint)] -- ^ ATS dependencies -> [(String, ATSConstraint)] -- ^ C Dependencies -> [(String, ATSConstraint)] -- ^ ATS build dependencies -> FilePath -- ^ Path to configuration file -> SetupScript -- ^ How to install an ATS library -> Bool -- ^ Whether to perform setup anyhow. -> IO () fetchDeps v cc' mStr setup' deps cdeps atsBld cfgPath als b' = unless (null deps && null cdeps && null atsBld && b' && False) $ do putStrLn "Resolving dependencies..." pkgSet <- unpack . defaultPkgs . decode <$> BSL.readFile cfgPath deps' <- setBuildPlan "ats" libDeps mStr pkgSet deps atsDeps' <- setBuildPlan "atsbld" libBldDeps mStr pkgSet atsBld cdeps' <- setBuildPlan "c" libDeps mStr pkgSet cdeps -- Set up actions d <- ( "lib/") <$> cpkgHome cc' let tgt' = getTgt cc' libs' = fmap (buildHelper False) (join deps') unpacked = fmap (over dirLens (pack d <>)) <$> cdeps' clibs = fmap (buildHelper False) (join unpacked) atsLibs = fmap (buildHelper False) (join atsDeps') cBuild = traverse_ (setup v cc') <$> (transpose . fmap reverse) unpacked atsBuild = traverse_ (atsPkgSetup als tgt') <$> (transpose . fmap reverse) atsDeps' -- Fetch all packages & build compiler parallel' $ join [ setup', libs', clibs, atsLibs ] let tagBuild str bld = unless (null bld) $ putStrLn (fold ["Building ", str, " dependencies..."]) *> sequence_ bld -- FIXME parallel' zipWithM_ tagBuild [ "C", "ATS" ] [ cBuild, atsBuild ] parallel' :: [IO ()] -> IO () parallel' = parallel_ . fmap extraWorkerWhileBlocked atsPkgSetup :: SetupScript -> Maybe String -> ATSDependency -> IO () atsPkgSetup als tgt' (ATSDependency lib' dirName' _ _ _ _ _ _ _) = do lib'' <- (<> unpack lib') <$> cpkgHome (GCC Nothing Nothing) b <- doesFileExist lib'' unless b $ do als tgt' (unpack lib') (unpack dirName') writeFile lib'' "" setup :: Verbosity -> CCompiler -- ^ C compiler to use -> ATSDependency -- ^ ATSDependency itself -> IO () setup v' cc' (ATSDependency lib' dirName' _ _ v _ _ _ _) = do lib'' <- (<> "-" <> show v) . ( unpack lib') <$> cpkgHome cc' b <- doesFileExist lib'' unless b $ do clibSetup v' cc' (unpack lib') (unpack dirName') writeFile lib'' "" getCompressor :: Text -> IO (ByteString -> ByteString) getCompressor s | ".tar.gz" `TL.isSuffixOf` s || ".tgz" `TL.isSuffixOf` s = pure Gzip.decompress | ".tar" `TL.isSuffixOf` s = pure id | ".tar.xz" `TL.isSuffixOf` s = pure Lzma.decompress | ".tar.bz2" `TL.isSuffixOf` s = pure Bzip.decompress | otherwise = unrecognized (unpack s) tarResponse :: Text -> FilePath -> ByteString -> IO () tarResponse url' dirName response = do compress <- getCompressor url' -- let f = Archive.unpackToDir dirName . BSL.toStrict . compress let f = Tar.unpack dirName . Tar.read . compress f response zipResponse :: FilePath -> ByteString -> IO () zipResponse dirName response = do let options = OptDestination dirName extractFilesFromArchive [options] (toArchive response) buildHelper :: Bool -> ATSDependency -> IO () buildHelper b (ATSDependency lib' dirName' url'' _ _ _ _ _ _) = do let (lib, dirName, url') = (lib', dirName', url'') & each %~ unpack isLib = bool "" "library " b needsSetup <- not <$> doesDirectoryExist (dirName ++ if b then "/atspkg.dhall" else "") when needsSetup $ do putStrLn ("Fetching " ++ isLib ++ lib ++ "...") manager <- newManager tlsManagerSettings initialRequest <- parseRequest url' response <- responseBody <$> httpLbs (initialRequest { method = "GET" }) manager putStrLn ("Unpacking " ++ isLib ++ lib ++ "...") if "zip" `TL.isSuffixOf` url'' then zipResponse dirName response else tarResponse url'' dirName response needsMove <- doesDirectoryExist (dirName "package") when needsMove $ do renameDirectory (dirName "package") "tempdir" removeDirectoryRecursive dirName renameDirectory "tempdir" dirName