-- | -- Module : RPM -- Copyright : (C) 2015-2017 Jens Petersen -- -- Maintainer : Jens Petersen -- -- Explanation: RPM utils -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. module RPM (buildRequires, derefSrcPkg, haskellSrcPkgs, Package, packageManager, pkgDir, repoquery, rpmInstall, rpmspec) where #if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,2)) #else import Control.Applicative ((<$>)) #endif import Control.Monad (when) import Data.List (isPrefixOf, isSuffixOf, nub, (\\)) import Data.Maybe (isJust, isNothing) import System.Directory (doesDirectoryExist, findExecutable) import System.FilePath (()) -- die is available in ghc-7.10 base-4.8 import System.Exit (ExitCode (..), exitFailure, exitWith) import System.IO (hPutStrLn, stderr) import Dists (Dist, distBranch, dists, distTag, releaseVersion) import Utils (cmd, removePrefix, removeSuffix, sudo, (+-+)) -- @since base 4.8.0.0 die :: String -> IO a die err = hPutStrLn stderr err >> exitFailure requireProgram :: String -> IO () requireProgram c = do mavail <- findExecutable c when (isNothing mavail) $ die (c ++ ": command not found") optionalProgram :: String -> IO Bool optionalProgram c = isJust <$> findExecutable c packageManager :: IO String packageManager = do havednf <- optionalProgram "dnf" if havednf then return "dnf" else requireProgram "yum" >> return "yum" rpmInstall :: [String] -> IO () rpmInstall rpms = do pkginstaller <- packageManager let (inst, arg) = if pkginstaller == "dnf" then ("dnf", "install") else ("yum", "localinstall") sudo inst $ ["-y", "--nogpgcheck", arg] ++ rpms repoquery :: Maybe String -> [String] -> IO String repoquery relver args = do havednf <- optionalProgram "dnf" let (prog, subcmd) = if havednf then ("dnf", ["repoquery", "--quiet"]) else ("repoquery", []) releasever = case relver of Nothing -> [] Just rv -> ["--releasever=" ++ rv] cmd prog (subcmd ++ releasever ++ args) repoquerySrc :: Dist -> String -> IO (Maybe String) repoquerySrc dist key = do havednf <- optionalProgram "dnf" let srcflag = if havednf then ["--qf=%{source_name}"] else ["--qf", "%{base_package_name}"] relver = releaseVersion dist repo = if dist `elem` dists then ["--repo=koji-buildroot", "--repofrompath", "koji-buildroot,http://kojipkgs.fedoraproject.org/repos" distTag dist "latest/x86_64/"] else [] res <- words <$> repoquery relver (srcflag ++ repo ++ ["--whatprovides", key]) return $ case res of [p] -> Just p ps | key `elem` ps -> Just key _ -> Nothing rpmspec :: [String] -> Maybe String -> FilePath -> IO String rpmspec args mqf spec = do let qf = maybe [] (\ q -> ["--queryformat", q]) mqf cmd "rpmspec" (["-q"] ++ ["--define", "ghc_version any"] ++ args ++ qf ++ [spec]) buildRequires :: FilePath -> IO [String] buildRequires spec = -- FIXME should resolve "pkgconfig()" etc map (head . words) . lines <$> rpmspec ["--buildrequires"] Nothing spec -- >>= mapM (whatProvides relver) type Package = String derefSrcPkg :: FilePath -> Dist -> Bool -> Package -> IO Package derefSrcPkg topdir dist verb pkg = if isHaskellDevelPkg pkg then do let lib = removeSuffix "-devel" pkg -- fixme: should check branch (dir) libExists <- doesDirectoryExist $ topdir lib if libExists then return lib else do -- todo: check bin has lib let bin = removePrefix "ghc-" lib binExists <- doesDirectoryExist $ topdir bin if binExists then return bin else derefSrcPkg topdir dist verb lib else do putStrLn $ "Repoquerying" +-+ pkg res <- repoquerySrc dist pkg case res of Nothing -> do putStrLn $ "Unknown package" +-+ removeSuffix "-devel" pkg exitWith (ExitFailure 1) Just s -> do when (pkg /= s && verb) $ putStrLn $ pkg +-+ "->" +-+ s return s isHaskellDevelPkg :: Package -> Bool isHaskellDevelPkg pkg = "ghc-" `isPrefixOf` pkg && ("-devel" `isSuffixOf` pkg) || pkg `elem`haskellTools haskellTools :: [Package] haskellTools = ["alex", "cabal-install", "gtk2hs-buildtools", "happy"] haskellSrcPkgs :: FilePath -> String -> [Package] -> IO [Package] haskellSrcPkgs topdir dist brs = do ghcLibs <- do let branch = distBranch dist ghcDir <- pkgDir "ghc" branch topdir filter isHaskellDevelPkg . words <$> rpmspec [] (Just "%{name}\n") (ghcDir "ghc.spec") let hdeps = filter (\ dp -> "ghc-" `isPrefixOf` dp || dp `elem` haskellTools) (brs \\ (["ghc-rpm-macros", "ghc-rpm-macros-extra"] ++ ghcLibs)) nub <$> mapM (derefSrcPkg topdir dist False) hdeps pkgDir :: String -> String -> FilePath -> IO FilePath pkgDir dir branch top = do b <- doesDirectoryExist $ top dir branch return $ top dir if b then branch else ""