packages feed

hackport-0.2.6: Portage/Host.hs

module Portage.Host
  ( getInfo -- :: IO [(String, String)]
  , LocalInfo(..)
  ) where

import Util (run_cmd)
import Data.Char (isSpace)
import Data.Maybe (fromJust, isJust)


data LocalInfo =
    LocalInfo { distfiles_dir :: String
              , overlay_list  :: [FilePath]
              , portage_dir   :: FilePath
              }

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 [ (fmap . fmap) parse_paludis_output (run_cmd "paludis --info")
                  , (fmap . fmap) parse_emerge_output  (run_cmd "emerge --info")
                  , return (Just defaultInfo)
                  ]
    where performMaybes [] = return Nothing
          performMaybes (act:acts) =
              do r <- act
                 if isJust r
                     then return r
                     else performMaybes acts

data LocalPaludisOverlay =
    LocalPaludisOverlay { repo_name :: String
                        , format    :: String
                        , location  :: FilePath
                        , distdir   :: FilePath
                        }

bad_paludis_overlay :: LocalPaludisOverlay
bad_paludis_overlay =
    LocalPaludisOverlay { repo_name = undefined
                        , format    = undefined
                        , location  = undefined
                        , distdir   = undefined
                        }

parse_paludis_output :: String -> LocalInfo
parse_paludis_output raw_data =
    foldl updateInfo defaultInfo $ parse_paludis_overlays raw_data
    where updateInfo info po =
              case (format po) of
                  "ebuild" | (repo_name po) /= "gentoo" -- hack, skip main repo
                      -> info{ distfiles_dir = distdir po -- we override last distdir here (FIXME?)
                             , overlay_list  = (location po) : overlay_list info
                             }
                  "ebuild" -- hack, main repo -- (repo_name po) == "gentoo"
                      -> info{ portage_dir = location po }

                  _   -> info

parse_paludis_overlays :: String -> [LocalPaludisOverlay]
parse_paludis_overlays raw_data =
    parse_paludis_overlays' (reverse $ lines raw_data) bad_paludis_overlay

-- parse in reverse order :]
parse_paludis_overlays' :: [String] -> LocalPaludisOverlay -> [LocalPaludisOverlay]
parse_paludis_overlays' [] _ = []
parse_paludis_overlays' (l:ls) info =
    case (words l) of
    -- look for "Repository <repo-name>:"
    ["Repository", r_name] -> info{repo_name = init r_name} :
                                      go bad_paludis_overlay
    -- else - parse attributes
    _ -> case (break (== ':') (refine l)) of
            ("location", ':':value)
                -> go info{location = refine value}
            ("distdir", ':':value)
                -> go info{distdir = refine value}
            ("format", ':':value)
                -> go info{format = refine value}
            _   -> go info
    where go = parse_paludis_overlays' ls
          refine = dropWhile isSpace

parse_emerge_output :: String -> LocalInfo
parse_emerge_output raw_data =
    foldl updateInfo defaultInfo $ lines raw_data
    where updateInfo info str =
              case (break (== '=') str) of
                  ("DISTDIR", '=':value)
                      -> info{distfiles_dir = unquote value}
                  ("PORTDIR", '=':value)
                      -> info{portage_dir = unquote value}
                  ("PORTDIR_OVERLAY", '=':value)
                      -> info{overlay_list = words $ unquote value}
                  _   -> info
          unquote = init . tail