module Portage.Host ( getInfo -- :: IO [(String, String)] , LocalInfo(..) ) where import Util (run_cmd) import qualified Data.List.Split as DLS import Data.Maybe (fromJust, isJust, catMaybes) import Control.Applicative ( (<$>) ) import qualified System.Directory as D import System.FilePath (()) import System.IO data LocalInfo = LocalInfo { distfiles_dir :: String , overlay_list :: [FilePath] , portage_dir :: FilePath } deriving (Read, Show) defaultInfo :: LocalInfo defaultInfo = LocalInfo { distfiles_dir = "/usr/portage/distfiles" , overlay_list = [] , portage_dir = "/usr/portage" } -- query paludis and then emerge getInfo :: IO LocalInfo getInfo = fromJust `fmap` performMaybes [ readConfig , performMaybes [ getPaludisInfo , askPortageq , return (Just defaultInfo) ] >>= showAnnoyingWarning ] where performMaybes [] = return Nothing performMaybes (act:acts) = do r <- act if isJust r then return r else performMaybes acts showAnnoyingWarning :: Maybe LocalInfo -> IO (Maybe LocalInfo) showAnnoyingWarning info = do hPutStr stderr $ unlines [ "-- Consider creating ~/" ++ hackport_config ++ " file with contents:" , show info , "-- It will speed hackport startup time a bit." ] return info -- relative to home dir hackport_config :: FilePath hackport_config = ".hackport" "repositories" -------------------------- -- fastest: config reading -------------------------- readConfig :: IO (Maybe LocalInfo) readConfig = do home_dir <- D.getHomeDirectory let config_path = home_dir hackport_config exists <- D.doesFileExist config_path case exists of True -> read <$> readFile config_path False -> return Nothing ---------- -- Paludis ---------- getPaludisInfo :: IO (Maybe LocalInfo) getPaludisInfo = fmap parsePaludisInfo <$> run_cmd "cave info" parsePaludisInfo :: String -> LocalInfo parsePaludisInfo text = let chunks = DLS.splitOn [""] . lines $ text repositories = catMaybes (map parseRepository chunks) in fromJust (mkLocalInfo repositories) where parseRepository :: [String] -> Maybe (String, (String, String)) parseRepository [] = Nothing parseRepository (firstLine:lns) = do name <- case words firstLine of ["Repository", nm] -> return (init nm) _ -> fail "not a repository chunk" let dict = [ (head ln, unwords (tail ln)) | ln <- map words lns ] location <- lookup "location" dict distfiles <- lookup "distdir" dict return (name, (location, distfiles)) mkLocalInfo :: [(String, (String, String))] -> Maybe LocalInfo mkLocalInfo repos = do (gentooLocation, gentooDistfiles) <- lookup "gentoo" repos let overlays = [ loc | (_, (loc, _dist)) <- repos ] return (LocalInfo { distfiles_dir = gentooDistfiles , portage_dir = gentooLocation , overlay_list = overlays }) --------- -- Emerge --------- askPortageq :: IO (Maybe LocalInfo) askPortageq = do distdir <- run_cmd "portageq distdir" portdir <- run_cmd "portageq get_repo_path / gentoo" hsRepo <- run_cmd "portageq get_repo_path / haskell" --There really ought to be both distdir and portdir, --but maybe no hsRepo defined yet. let info = if any (==Nothing) [distdir,portdir] then Nothing else Just LocalInfo { distfiles_dir = grab distdir , portage_dir = grab portdir , overlay_list = iffy hsRepo } --init: kill newline char where grab = init . fromJust iffy Nothing = [] iffy (Just repo) = [init repo] return info