hackport-0.8.5.2: src/Portage/Host.hs
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, mapMaybe, fromMaybe)
import qualified System.Directory as D
import System.FilePath ((</>))
import Hackport.Dirs (hackportDir)
import Control.Applicative ((<|>))
import Control.Monad (guard)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.State.Strict (MonadState)
import Control.Monad.Trans.Maybe (MaybeT(..))
import Hackport.Env (HasGlobalEnv, WarningBuffer)
import Util (warn)
data LocalInfo =
LocalInfo { distfiles_dir :: String
, overlay_list :: [FilePath]
, portage_dir :: FilePath
} deriving (Read, Show)
defaultInfo :: LocalInfo
defaultInfo = LocalInfo { distfiles_dir = "/var/cache/distfiles"
, overlay_list = []
, portage_dir = "/var/db/repos/gentoo"
}
-- query paludis and then emerge
getInfo :: (HasGlobalEnv m, MonadIO m, MonadState WarningBuffer m)
=> m LocalInfo
getInfo = fromMaybe defaultInfo <$> runMaybeT (readConfig <|> getInfoWithWarning)
where
getInfoWithWarning = MaybeT $ do
configPath <- hackportConfig
info <- runMaybeT $ getPaludisInfo <|> askPortageq
warn $ configWarning configPath info
pure info
configWarning configPath info = unlines
[ "-- Consider creating " ++ configPath ++ " file with contents:"
, show info
, "-- It will speed hackport startup time a bit."
]
-- | Where @repositories@ config file is located
hackportConfig :: MonadIO m => m FilePath
hackportConfig = (</> "repositories") <$> hackportDir
--------------------------
-- fastest: config reading
--------------------------
readConfig :: MonadIO m => MaybeT m LocalInfo
readConfig = do
configPath <- hackportConfig
liftIO (D.doesFileExist configPath) >>= guard
MaybeT $ liftIO $ read <$> readFile configPath
----------
-- Paludis
----------
getPaludisInfo :: MonadIO m => MaybeT m LocalInfo
getPaludisInfo = MaybeT $ fmap parsePaludisInfo <$> run_cmd "cave info"
parsePaludisInfo :: String -> LocalInfo
parsePaludisInfo text =
let chunks = DLS.splitOn [""] . lines $ text
repositories = mapMaybe 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 = [ (lnHead, unwords lnTail) | (lnHead:lnTail) <- 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 :: MonadIO m => MaybeT m 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.
guard $ all isJust [distdir,portdir]
pure LocalInfo
{ distfiles_dir = grab distdir
, portage_dir = grab portdir
, overlay_list = iffy hsRepo
}
where
--init: kill newline char
grab = init . fromJust
iffy Nothing = []
iffy (Just repo) = [init repo]