packages feed

fquery-0.2.2: Adelie/Portage.hs

-- Portage.hs
--
-- Portage directories and file paths.

module Adelie.Portage (
  portageTree,
  portageDB,
  useDesc,
  useDescPackage,
  useExpDescDir,

  dropVersion,
  concatPath,
  fullnameFromCatName,
  allInstalledPackages,
  findInstalledPackages
) where

import Data.Char         (isDigit)
import System.Directory  (getDirectoryContents, doesDirectoryExist)
import Data.List         (sort)
import Control.Monad     (liftM)

import Adelie.FileEx
import Adelie.ListEx
import Adelie.Config

-- Skips non-directory entries from returned list
-- (symlinks to world file in our case)
-- racy actually
safeGetDirectoryContents :: FilePath -> IO [FilePath]
safeGetDirectoryContents dir =
    do yet <- doesDirectoryExist dir
       if yet then getDirectoryContents dir
              else return []

portageProfiles :: String
portageProfiles = portageTree ++ "/profiles"

-- Where the global use flag descriptions are, 'use.desc'.
useDesc :: String
useDesc = portageProfiles ++ "/use.desc"

-- Where the package specific use flag descriptions are, 'use.local.desc'.
useDescPackage :: String
useDescPackage = portageProfiles ++ "/use.local.desc"

-- Where the USE Expand descriptions are.
useExpDescDir :: String
useExpDescDir = portageProfiles ++ "/desc"

----------------------------------------------------------------

dropVersion :: String -> String
dropVersion [] = []
dropVersion ('-':x:xs)
  | isDigit x = []
  | otherwise = '-':x:dropVersion xs
dropVersion (x:xs) = x:dropVersion xs

fullnameFromCatName :: (String, String) -> String
fullnameFromCatName (cat, name) = cat ++ '/':name

----------------------------------------------------------------

allInstalledPackages :: IO [(String, String)]
allInstalledPackages = do
  cats <- liftM (sort.filter filterHidden) (safeGetDirectoryContents portageDB)
  concatMapM allInstalledPackagesInCategory cats

allInstalledPackagesInCategory :: String -> IO [(String, String)]
allInstalledPackagesInCategory cat = do
  names <- liftM (sort.filter filterHidden) (safeGetDirectoryContents path)
  return $ map (\ a -> (cat, a)) names
  where path = portageDB ++ '/':cat

----------------------------------------------------------------

findInstalledPackages :: [String] -> IO [(String, String)]
findInstalledPackages names = concatMapM findInstPackages names

findInstPackages :: String -> IO [(String, String)]
findInstPackages name =
  if null b
    then findInstPackages' a
    else findInstPackagesInCategory a b
  where (a, b) = break2 (== '/') name

findInstPackages' :: String -> IO [(String, String)]
findInstPackages' pack = do
  cats  <- liftM (sort.filter filterHidden) (safeGetDirectoryContents portageDB)
  concatMapM (flip findInstPackagesInCategory pack) cats

findInstPackagesInCategory :: String -> String -> IO [(String, String)]
findInstPackagesInCategory cat pack = do
  packs <- liftM (sort.filter cond) (safeGetDirectoryContents (portageDB++'/':cat))
  return (zip (repeat cat) packs)
  where
    cond ('.':_) = False
    cond p = (pack == p) || (pack == dropVersion p)

----------------------------------------------------------------
filterHidden :: String -> Bool
filterHidden ('.':_) = False
filterHidden _ = True