fquery-0.2.1: Adelie/Depend.hs
-- Depend.hs
--
-- Module for parsing DEPEND and RDEPEND files, located in
-- portageDB/cateogry/package/.
module Adelie.Depend (
Version,
Dependency(..),
dependFromCatName,
readDepend,
putDependency
) where
import Data.Char (isSpace)
import Data.List (nub)
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Language
import Text.ParserCombinators.Parsec.Token
import Adelie.Portage
type Version = String
data Dependency
= GreaterEqual String Version
| Equal String Version
| Unstable String Version
| NotInstalled String
| Any String
deriving (Eq, Show)
----------------------------------------------------------------
dependFromCatName :: (String, String) -> String
dependFromCatName (cat, name) = concatPath [portageDB,cat,name,"RDEPEND"]
----------------------------------------------------------------
readDepend :: FilePath -> [String] -> IO [Dependency]
readDepend fn iUse = do
r <- (start_parser fn) `catch` (\ _ -> return $ Right [])
case r of
Left err -> putStr "Parse error at " >> print err >> error "Aborting"
Right x -> return $ nub x
where start_parser = parseFromFile (dependParser iUse)
----------------------------------------------------------------
putDependency :: Dependency -> IO ()
putDependency (GreaterEqual p v) = putStr $ ">=" ++ p ++ '-':v
putDependency (Equal p v) = putStr $ '=':p ++ '-':v
putDependency (Unstable p v) = putStr $ '~':p ++ '-':v
putDependency (NotInstalled p) = putStr $ '!':p
putDependency (Any p) = putStr p
----------------------------------------------------------------
dependParser :: [String] -> Parser [Dependency]
dependParser iUse = do
_skip <- spaces
packages <- many (dependParser' iUse)
eof
return $ concat packages
dependParser' :: [String] -> Parser [Dependency]
dependParser' iUse = lexeme tp pp
where tp = makeTokenParser emptyDef
pp = parseOr iUse
<|> parsePackageOrUse iUse
parseOr :: [String] -> Parser [Dependency]
parseOr iUse = do { string "||"
; spaces
; parseBrackets iUse
}
<|>
parseBrackets iUse
parsePackageOrUse :: [String] -> Parser [Dependency]
parsePackageOrUse iUse =
do { p <- parsePackageOrUseWord
; do { char '?' -- useFlag
; spaces
; r <- parseBrackets iUse
; let filt | head p == '!' = not $ (tail p) `elem` iUse
| otherwise = p `elem` iUse
; if filt
then return r
else return []
}
<|> return [toDependency p]
}
parsePackageOrUseWord :: Parser String
parsePackageOrUseWord = do { result <- many1 (satisfy cond)
-- skip[use]
-- TODO: add it to output
; optionMaybe (do { char '['
; _use <- many1 (satisfy (/= ']'))
; char ']'
-- ; return use
; return ()
})
; return result
}
where
cond '?' = False
cond ')' = False
cond '[' = False
cond x = not $ isSpace x
parseBrackets :: [String] -> Parser [Dependency]
parseBrackets iUse = do { char '('
; spaces
; r <- manyTill (dependParser' iUse) (try (char ')'))
; return $ concat r
}
----------------------------------------------------------------
breakVersion :: String -> (String, String)
breakVersion str = (n, v)
where n = dropVersion str
v = drop (length n+1) str
toDependency :: String -> Dependency
toDependency ('>':'=':str) = (GreaterEqual n v)
where (n, v) = breakVersion str
toDependency ('=':str) = (Equal n v)
where (n, v) = breakVersion str
toDependency ('~':str) = (Unstable n v)
where (n, v) = breakVersion str
toDependency ('!':n) = (NotInstalled n)
toDependency n = (Any n)