fquery (empty) → 0.2.1
raw patch · 29 files changed
+1619/−0 lines, 29 filesdep +basedep +directorydep +haskell98setup-changed
Dependencies added: base, directory, haskell98, parsec, process, regex-compat, unix
Files
- Adelie/Colour.hs +55/−0
- Adelie/CompareVersion.hs +35/−0
- Adelie/Config.hs.in +13/−0
- Adelie/Contents.hs +94/−0
- Adelie/Depend.hs +140/−0
- Adelie/ListEx.hs +46/−0
- Adelie/Options.hs +13/−0
- Adelie/Portage.hs +102/−0
- Adelie/Pretty.hs +31/−0
- Adelie/Provide.hs +22/−0
- Adelie/QChangelog.hs +169/−0
- Adelie/QCheck.hs +77/−0
- Adelie/QDepend.hs +75/−0
- Adelie/QHasUse.hs +38/−0
- Adelie/QList.hs +56/−0
- Adelie/QOwn.hs +79/−0
- Adelie/QSize.hs +61/−0
- Adelie/QUse.hs +75/−0
- Adelie/QWant.hs +26/−0
- Adelie/Use.hs +34/−0
- Adelie/UseDesc.hs +86/−0
- Adelie/opts.c +13/−0
- Adelie/opts.h +9/−0
- LICENCE.txt +23/−0
- Main.hs +164/−0
- Setup.hs +3/−0
- TODO +4/−0
- configure +23/−0
- fquery.cabal +53/−0
+ Adelie/Colour.hs view
@@ -0,0 +1,55 @@+-- Colour.hs+--+-- Escape codes for colouring in output.++module Adelie.Colour (+ gray, inGray,+ red, inRed,+ green, inGreen,+ yellow, inYellow,+ blue, inBlue,+ magenta, inMagenta,+ cyan, inCyan,+ white, inWhite,+ off,+ off2+) where++import Monad (when)++import Adelie.Options++gray, red, green, yellow, blue, magenta, cyan, white, off, off2 :: IO ()++gray = whenM colourEnabled $ putStr "\27[30;01m"+red = whenM colourEnabled $ putStr "\27[31;01m"+green = whenM colourEnabled $ putStr "\27[32;01m"+yellow = whenM colourEnabled $ putStr "\27[33;01m"+blue = whenM colourEnabled $ putStr "\27[34;01m"+magenta = whenM colourEnabled $ putStr "\27[35;01m"+cyan = whenM colourEnabled $ putStr "\27[36;01m"+white = whenM colourEnabled $ putStr "\27[37;01m"+off = whenM colourEnabled $ putStr "\27[0m"+off2 = do+ true <- colourEnabled+ if true+ then putStrLn "\27[0m"+ else putChar '\n'++whenM :: IO Bool -> IO () -> IO ()+whenM cond f = cond >>= (flip when f)++----------------------------------------------------------------++inGray, inRed, inGreen, inYellow :: IO () -> IO ()+inBlue, inMagenta, inCyan, inWhite :: IO () -> IO ()++inGray f = gray >> f >> off+inRed f = red >> f >> off+inGreen f = yellow >> f >> off+inYellow f = yellow >> f >> off+inBlue f = blue >> f >> off+inMagenta f = magenta >> f >> off+inCyan f = cyan >> f >> off+inWhite f = white >> f >> off+
+ Adelie/CompareVersion.hs view
@@ -0,0 +1,35 @@+-- CompareVersion.hs+--+-- Version string comparitor, which handles numbers differently: 1.10 > 1.9.++module Adelie.CompareVersion (compareVersion) where++import Char (isDigit)++import Adelie.ListEx (digitsToInt)++----------------------------------------------------------------++compareVersion :: String -> String -> Ordering+compareVersion = cmpA++cmpA :: String -> String -> Ordering+cmpA a0 b0+ | r == EQ = cmpB as bs+ | otherwise = r+ where (a, as) = break (not.isDigit) a0+ (b, bs) = break (not.isDigit) b0+ r = compare (digitsToInt a) (digitsToInt b)++cmpB :: String -> String -> Ordering+cmpB [] [] = EQ+cmpB ('*':_) _ = EQ+cmpB _ ('*':_) = EQ+cmpB [] _ = LT+cmpB _ [] = GT+cmpB a0 b0+ | r == EQ = cmpA as bs+ | otherwise = r+ where (a, as) = break isDigit a0+ (b, bs) = break isDigit b0+ r = compare a b
+ Adelie/Config.hs.in view
@@ -0,0 +1,13 @@+-- Config.hs+--+-- Auto-generated.++module Adelie.Config (+ portageTree,+ portageDB+) where++portageTree, portageDB :: String++portageTree = @@PortageTree@@+portageDB = @@PortageDB@@
+ Adelie/Contents.hs view
@@ -0,0 +1,94 @@+-- Contents.hs+--+-- Module for parsing CONTENTS files, located in portageDB/category/package/.++module Adelie.Contents (+ Contents(..),++ contentsFromCatName,+ putContents,+ putContentsLn,+ readContents+) where++import Char (isDigit, isHexDigit, isSpace)+import IO++import Adelie.Colour+import Adelie.ListEx+import Adelie.Portage++data Contents+ = Dir String+ | Obj String String Int+ | Sym String String Int+ deriving Show++----------------------------------------------------------------++contentsFromCatName :: (String, String) -> String+contentsFromCatName (cat, name) = concatPath [portageDB,cat,name,"CONTENTS"]++----------------------------------------------------------------++readContents :: (Contents -> a -> IO (Bool, a)) -> FilePath -> a -> IO a+readContents f fn a = do+ r <- try read'+ case r of+ Left _ -> return a+ Right a' -> return a'+ where+ read' =+ bracket (openFile fn ReadMode)+ hClose+ (readContents' f a)++readContents' :: (Contents -> a -> IO (Bool, a)) -> a -> Handle -> IO a+readContents' f a fp = do+ eof <- hIsEOF fp+ if eof+ then return a+ else do+ ln <- hGetLine fp+ (done, a') <- f (contentsParser ln) a+ if done+ then return a'+ else readContents' f a' fp++----------------------------------------------------------------++putContents, putContentsLn :: Contents -> IO ()+putContents = putContents' off+putContentsLn = putContents' off2++putContents' :: IO () -> Contents -> IO ()+putContents' f (Dir d) = blue >> putStr d >> f+putContents' f (Obj o _ _) = white >> putStr o >> f+putContents' f (Sym l t _) = cyan >> putStr (l ++ " -> " ++ t) >> f++----------------------------------------------------------------++contentsParser :: String -> Contents+contentsParser ('d':'i':'r':' ':dir) = (Dir dir)++contentsParser ('o':'b':'j':' ':ln0) = (Obj obj md5 time)+ where ln1 = dropWhile isSpace $ reverse ln0+ (time', ln2) = break2 (not.isDigit) ln1+ (md5', obj') = break2 (not.isHexDigit) ln2+ obj = reverse obj'+ md5 = reverse md5'+ time = digitsToInt (reverse time')++contentsParser ('s':'y':'m':' ':ln0) = (Sym link target time)+ where (link, ln1) = breakLink ln0+ ln2 = reverse ln1+ (time', target') = break2 (not.isDigit) ln2+ target = reverse target'+ time = digitsToInt (reverse time')+contentsParser cont = error $ "contentsParser: 'dir: /obj: /sym: ' not found in " ++ show cont++breakLink :: String -> (String, String)+breakLink (' ':'-':'>':' ':xs) = ([], xs)+breakLink (x:xs) = (x:as, bs)+ where (as, bs) = breakLink xs+breakLink [] = error "breakLink: ' -> ' not found"
+ Adelie/Depend.hs view
@@ -0,0 +1,140 @@+-- 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)
+ Adelie/ListEx.hs view
@@ -0,0 +1,46 @@+-- ListEx.hs+--+-- Extra list functions.++module Adelie.ListEx (+ break2,+ concatMapM,+ digitsToInt,+ dropTail,+ dropUntilAfter,+ foldMUntil,+ pad+) where++import Char (digitToInt)+import Data.List (foldl')+import Monad (liftM)++----------------------------------------------------------------++break2 :: (a -> Bool) -> [a] -> ([a], [a])+break2 f l = (h, drop 1 t)+ where (h, t) = break f l++concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]+concatMapM f xs = liftM concat $ mapM f xs++digitsToInt :: String -> Int+digitsToInt = foldl' (\ a b -> a*10 + digitToInt b) 0++dropTail :: Int -> [a] -> [a]+dropTail n s = take (length s-n) s++dropUntilAfter :: (a -> Bool) -> [a] -> [a]+dropUntilAfter f = dropWhile f . dropWhile (not.f)++foldMUntil :: Monad m => (a -> b -> m a) -> (a -> Bool) -> a -> [b] -> m a+foldMUntil _ _ a [] = return a+foldMUntil f g a (x:xs) = do+ a' <- f a x+ case g a' of+ True -> return a'+ False -> foldMUntil f g a' xs++pad :: Int -> a -> [a] -> [a]+pad n a str = take n (str ++ repeat a)
+ Adelie/Options.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}++-- Options.hs+--+-- We keep some globals in C so we don't have to pass them around everywhere.++module Adelie.Options (+ colourEnabled,+ setColourEnabled+) where++foreign import ccall unsafe "opts.h colour_enabled" colourEnabled :: IO Bool+foreign import ccall unsafe "opts.h set_colour_enabled" setColourEnabled :: Bool -> IO ()
+ Adelie/Portage.hs view
@@ -0,0 +1,102 @@+-- Portage.hs+--+-- Portage directories and file paths.++module Adelie.Portage (+ portageTree,+ portageDB,+ useDesc,+ useDescPackage,++ dropVersion,+ concatPath,+ fullnameFromCatName,+ allInstalledPackages,+ findInstalledPackages+) where++import Data.Char (isDigit)+import System.Directory (getDirectoryContents, doesDirectoryExist)+import Data.List (intersperse, sort)+import Control.Monad (liftM)++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"++----------------------------------------------------------------++dropVersion :: String -> String+dropVersion [] = []+dropVersion ('-':x:xs)+ | isDigit x = []+ | otherwise = '-':x:(dropVersion xs)+dropVersion (x:xs) = x:(dropVersion xs)++concatPath :: [String] -> String+concatPath = concat.intersperse "/"++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
+ Adelie/Pretty.hs view
@@ -0,0 +1,31 @@+-- Pretty.hs+--+-- Colourful output.++module Adelie.Pretty (+ putCatName,+ putCatNameLn,+ putNum,+ putNumLn+) where++import Adelie.Colour++----------------------------------------------------------------++putCatName, putCatNameLn :: (String, String) -> IO ()+putCatName = putCatName' off+putCatNameLn = putCatName' off2++putCatName' :: IO () -> (String, String) -> IO ()+putCatName' f (c, n) =+ inYellow (putStr c) >> putChar '/' >> yellow >> putStr n >> f++----------------------------------------------------------------++putNum, putNumLn :: Int -> IO ()+putNum = putNum' off+putNumLn = putNum' off2++putNum' :: IO () -> Int -> IO ()+putNum' f n = cyan >> putStr (show n) >> f
+ Adelie/Provide.hs view
@@ -0,0 +1,22 @@+-- Provide.hs+--+-- Module for parsing PROVIDE files, located in portageDB/category/package/.++module Adelie.Provide (+ provideFromCatName,+ readProvide+) where++import Monad (liftM)++import Adelie.Portage++----------------------------------------------------------------++provideFromCatName :: (String, String) -> String+provideFromCatName (cat,name) = concatPath [portageDB,cat,name,"PROVIDE"]++----------------------------------------------------------------++readProvide :: FilePath -> IO [String]+readProvide fn = (liftM words (readFile fn)) `catch` (\ _ -> return [])
+ Adelie/QChangelog.hs view
@@ -0,0 +1,169 @@+-- QChangelog.hs+--+-- Module to find the changelog of a package.++module Adelie.QChangelog (+ qChangelog,+ qLogFile+) where++import Char (isDigit, isSpace)+import Monad (unless)++import Adelie.Colour+import Adelie.CompareVersion+import Adelie.ListEx+import Adelie.Portage+import Adelie.Pretty++----------------------------------------------------------------++qLogFile :: [String] -> IO ()+qLogFile args = mapM_ (putStrLn.logFile) =<< findInstalledPackages args++logFile :: (String, String) -> String+logFile (cat, name) = + portageTree ++ '/':cat ++ '/':(dropVersion name) ++ "/ChangeLog"++----------------------------------------------------------------++qChangelog :: [String] -> IO ()+qChangelog [] = return ()+qChangelog [x] = mapM_ (changelog Nothing) =<< findInstalledPackages [x]+qChangelog (x:y:_) = mapM_ (changelog (Just y)) =<< findInstalledPackages [x]++changelog :: Maybe String -> (String, String) -> IO ()+changelog end catname@(_, name) = do+ putStr "ChangeLog since " >> putCatNameLn catname+ log' <- readFile (logFile catname)+ puts name end log'++----------------------------------------------------------------++puts :: String -> Maybe String -> String -> IO ()++puts _ _ [] = return ()+puts inst end ('#':l) = puts inst end (dropUntilAfter isNewLine l)++puts inst end ('*':l0) = do+ case maybeCompareVersion package end of+ GT -> puts inst end next+ _ -> case compareVersion inst package of+ LT -> putSection package date >> putDesc ls >> puts inst end next+ _ -> puts inst end next+ where (section, next) = breakSection l0+ (line, ls) = break2 isNewLine section+ (l1, l2) = break2 ('(' ==) line+ package = takeWhile (not.isSpace) l1+ date = takeWhile (')' /=) l2++puts inst end (_:ls) = puts inst end ls++maybeCompareVersion :: String -> Maybe String -> Ordering+maybeCompareVersion _ Nothing = LT+maybeCompareVersion a (Just b) = compareVersion a b++----------------------------------------------------------------++breakSection :: String -> (String, String)+breakSection str = (reverse h, t)+ where (h, t) = breakSection' [] str++breakSection' :: String -> String -> (String, String)+breakSection' acc [] = (acc, [])+breakSection' acc nx@('\n':'*':_) = (acc, nx)+breakSection' acc (x:xs) = breakSection' (x:acc) xs++----------------------------------------------------------------++putSection :: String -> String -> IO ()+putSection package date = do+ putStr "* " >> inYellow (putStr package) + putStr " (" >> inWhite (putStr date) >> putStrLn ")"++----------------------------------------------------------------++putDesc :: String -> IO ()+putDesc [] = return ()+putDesc str = mapM_ putDesc' ls+ where ls = doublelines (dropWhile isNewLine str)++putDesc' :: String -> IO ()+putDesc' str = do+ if beginsWithDate (dropWhile isSpace str)+ then do+ putHeader header+ putBody body+ else+ putBody str+ where (header, body) = break2 (':' ==) str++doublelines :: String -> [String]+doublelines str =+ case t of+ [] -> h : []+ (_:'\n':xs) -> h : doublelines xs+ (_:xs) -> let (l0:l1) = doublelines xs + in (h ++ ('\n' : l0)) : l1+ where (h, t) = break ('\n' ==) str++beginsWithDate :: String -> Bool+beginsWithDate [] = False+beginsWithDate [_] = False+beginsWithDate (x:y:_)+ | not (isDigit x) = False+ | not (isDigitOrSpace y) = False+ | otherwise = True++----------------------------------------------------------------++putHeader :: String -> IO ()+putHeader str0 = do+ putChar '\n'+ inWhite (putStr date)+ unless (null name) (putStr name)+ red >> putStr ('<':mail) >> putChar '>' >> off2+ putStr " " >> putFiles 76 files+ where+ (date, str1) = break2 (';' ==) str0+ (name, str2) = break2 ('<' ==) str1+ (mail, str3) = break2 ('>' ==) str2+ files = words str3++putFiles :: Int -> [String] -> IO ()+putFiles _ [] = putChar '\n'+putFiles rem' (";":files) = putFiles rem' files+putFiles rem' (f:files) =+ if rem' < len+ then do+ putChar '\n' >> putStr " "+ putFiles 76 (f:files)+ else do+ cyan+ if (last f == ',')+ then putStr (dropTail 1 f) >> off >> putStr ", "+ else putStr f >> off >> putChar ' '+ putFiles (rem' - len - 1) files+ where len = length f++----------------------------------------------------------------++putBody :: String -> IO ()+putBody [] = putChar '\n'++putBody ('#':c0) =+ case bug of+ [] -> putChar '#' >> putBody cs+ _ -> inMagenta (putStr ('#':bug)) >> putBody cs+ where (bug, cs) = span (isDigitOrSpace) c0++putBody (c:cs) = putChar c >> putBody cs++----------------------------------------------------------------++isNewLine :: Char -> Bool+isNewLine '\n' = True+isNewLine _ = False++isDigitOrSpace :: Char -> Bool+isDigitOrSpace x = isDigit x || isSpace x
+ Adelie/QCheck.hs view
@@ -0,0 +1,77 @@+-- QMD5sum.hs+--+-- Check MD5sums and timestamps of installed packages.++module Adelie.QCheck (qCheck) where++import Char (isHexDigit)+import IO++import System.Process (runProcess, waitForProcess, ProcessHandle)+import System.Posix.Files (getFileStatus)+import System.Posix.IO (createPipe, fdToHandle)++import Adelie.Colour+import Adelie.Contents+import Adelie.Portage+import Adelie.Pretty++-- Good, Bad+type Count = (Int, Int)++----------------------------------------------------------------++qCheck :: [String] -> IO ()+qCheck args = mapM_ check =<< findInstalledPackages args++check :: (String, String) -> IO ()+check catname = do+ putStr "Checking " >> putCatNameLn catname+ (g, b) <- readContents check' contents (0, 0)+ putNum g >> putStr " out of " >> putNum (b+g) >> putStrLn " files good"+ putChar '\n'+ where contents = contentsFromCatName catname++check' :: Contents -> Count -> IO (Bool, Count)++check' (Dir _) (g, b) = return (False, (g+1, b))++check' (Obj o m _) (g, b) = do+ r <- try (getFileStatus o)+ case r of+ Left _e -> do+ inRed (putStr "!!! ") >> putStr o >> putStrLn " does not exist"+ return (False, (g, b+1))+ Right _stat -> do+ (rd, wr) <- createPipeHandle+ runMD5sum o (Just wr) >>= waitForProcess+ ln <- hGetLine rd+ hClose rd+ hClose wr+ if m == (takeWhile isHexDigit ln)+ then return (False, (g+1, b))+ else putMD5error o >> return (False, (g, b+1))++check' (Sym _ _ _) (g, b) = return (False, (g+1, b))++----------------------------------------------------------------++createPipeHandle :: IO (Handle, Handle)+createPipeHandle = do+ (read', write) <- createPipe+ hRead <- fdToHandle read'+ hWrite <- fdToHandle write+ return (hRead, hWrite)++----------------------------------------------------------------+runMD5sum :: String+ -> Maybe Handle+ -> IO ProcessHandle+runMD5sum f stdout' = runProcess md5sum [f] Nothing Nothing stdin' stdout' stderr'+ where md5sum = "/usr/bin/md5sum"+ stdin' = Nothing+ stderr' = Nothing++putMD5error :: String -> IO ()+putMD5error file =+ inRed (putStr "!!! ") >> putStrLn (file ++ " has incorrect md5sum")
+ Adelie/QDepend.hs view
@@ -0,0 +1,75 @@+-- QDepend.hs+--+-- Module to list packages depending on an installed package.++module Adelie.QDepend (qDepend) where++import Adelie.Colour+import Adelie.CompareVersion+import Adelie.Depend+import Adelie.ListEx+import Adelie.Portage+import Adelie.Pretty+import Adelie.Provide+import Adelie.Use++----------------------------------------------------------------++qDepend :: [String] -> IO ()+qDepend [] = return ()+qDepend args = qDepend' =<< findInstalledPackages args++qDepend' :: [(String, String)] -> IO ()+qDepend' catnames = do+ allPacks <- allInstalledPackages+ let allPacks2 = map fullnameFromCatName allPacks+ mapM_ (dep allPacks2) catnames++dep :: [String] -> (String, String) -> IO ()+dep allPacks catname = do+ putStr "Packages depending on " >> putCatNameLn catname+ provide <- readProvide fnProvide+ mapM_ (dep' (fullname:provide)) allPacks+ putChar '\n'+ where fullname = fullnameFromCatName catname+ fnProvide = provideFromCatName catname++dep' :: [String] -> String -> IO ()+dep' provided fullname =+ readUse fnIUse >>= readDepend fnDepend >>= puts fullname provided+ where fnDepend = concatPath [portageDB,fullname,"RDEPEND"]+ fnIUse = concatPath [portageDB,fullname,"USE"]++puts :: String -> [String] -> [Dependency] -> IO ()+puts str provided iWant = mapM_ print' perms+ where perms = [ (p, w) | p <- provided, w <- iWant, w `satisfiedBy` p ]+ print' (_p, w) =+ white >> putStr (pad 32 ' ' str) >> off >>+ putStr "\t( " >> putDependency w >> putStrLn " )"++-------------------------------------------------------------++breakVersion :: String -> (String, String)+breakVersion str = (n, v)+ where n = dropVersion str+ v = drop (length n+1) str++satisfiedBy :: Dependency -> String -> Bool++(GreaterEqual wantName wantVer) `satisfiedBy` provided =+ (wantName == provName) && (compareVersion provVer wantVer) /= LT+ where (provName, provVer) = breakVersion provided++(Equal wantName wantVer) `satisfiedBy` provided = + (wantName == provName) && (compareVersion provVer wantVer) == EQ+ where (provName, provVer) = breakVersion provided++(Unstable wantName wantVer) `satisfiedBy` provided =+ (wantName == provName) && (compareVersion provVer wantVer) == EQ+ where (provName, provVer) = breakVersion provided++(NotInstalled _) `satisfiedBy` _ = False++(Any wantName) `satisfiedBy` provided =+ wantName == provName+ where provName = dropVersion provided
+ Adelie/QHasUse.hs view
@@ -0,0 +1,38 @@+-- QHasUse.hs+--+-- Module to list all installed packages with a particular use flag.++module Adelie.QHasUse (qHasUse) where++import Monad (when)++import Adelie.Colour+import Adelie.Portage+import Adelie.Pretty+import Adelie.Use++----------------------------------------------------------------++qHasUse :: [String] -> IO ()+qHasUse [] = return ()+qHasUse args = qHasUse' args =<< allInstalledPackages ++qHasUse' :: [String] -> [(String, String)] -> IO ()+qHasUse' uses catnames = mapM_ (hasUse catnames) uses++hasUse :: [(String, String)] -> String -> IO ()+hasUse catnames use = do+ putStr "Packages installed with " >> putUse use >> putStrLn " USE flag"+ mapM_ (flip hasUse' use) catnames+ putChar '\n'++hasUse' :: (String, String) -> String -> IO ()+hasUse' catname use = do+ iUse <- readIUse fnIUse+ when (use `elem` iUse) (putCatNameLn catname)+ where fnIUse = iUseFromCatName catname++----------------------------------------------------------------++putUse :: String -> IO ()+putUse u = blue >> putStr u >> off
+ Adelie/QList.hs view
@@ -0,0 +1,56 @@+-- QList.hs+--+-- Module to list the contents of an installed package.++module Adelie.QList (+ ListTypes(..),++ qList+) where++import Adelie.Contents+import Adelie.Portage+import Adelie.Pretty++data ListTypes+ = ListDirs+ | ListFiles+ | ListLinks+ | ListAll+ deriving Eq++---------------------------------------------------------------- ++qList :: ListTypes -> [String] -> IO ()+qList types args = mapM_ (list puts) =<< findInstalledPackages args+ where+ puts = case types of+ ListDirs -> putsD+ ListFiles -> putsF+ ListLinks -> putsL+ _ -> putsA++list :: (Contents -> () -> IO (Bool, ()))+ -> (String, String)+ -> IO ()+list puts catname = do+ putStr "Contents of " >> putCatNameLn catname+ readContents puts contents ()+ putChar '\n'+ where contents = contentsFromCatName catname++----------------------------------------------------------------++putsA, putsD, putsF, putsL :: Contents -> () -> IO (Bool, ())++putsA (Obj o _ _) _ = putStrLn o >> return (False, ())+putsA c _ = putContentsLn c >> return (False, ())++putsD c@(Dir _) _ = putContentsLn c >> return (False, ())+putsD _ _ = return (False, ())++putsF (Obj o _ _) _ = putStrLn o >> return (False, ())+putsF _ _ = return (False, ())++putsL c@(Sym _ _ _)_= putContentsLn c >> return (False, ())+putsL _ _ = return (False, ())
+ Adelie/QOwn.hs view
@@ -0,0 +1,79 @@+-- QOwn.hs+--+-- Module to query who owns a particular file.++module Adelie.QOwn (+ qOwn,+ qOwnRegex+) where++import List (delete)+import Monad (when)+import Text.Regex (Regex, matchRegex, mkRegex)++import Adelie.Contents+import Adelie.ListEx+import Adelie.Portage+import Adelie.Pretty++----------------------------------------------------------------++qOwn :: [String] -> IO ()+qOwn [] = return ()+qOwn args = do+ foldMUntil qOwn' null args =<< allInstalledPackages+ putChar '\n'++qOwn' :: [String] -> (String, String) -> IO [String]+qOwn' files catname = readContents (puts catname) contents files+ where contents = contentsFromCatName catname++----------------------------------------------------------------++puts :: (String, String) -> Contents -> [String] -> IO (Bool, [String])+puts catname c fs =+ if c `contentsElem` fs+ then do+ let fs' = deleteContent c fs+ putCatName catname >> putStr " (" >> putContents c >> putStrLn ")"+ return (null fs', fs')+ else+ return (False, fs)++contentsElem :: Contents -> [String] -> Bool+(Dir d) `contentsElem` fs = d `elem` fs+(Obj o _ _) `contentsElem` fs = o `elem` fs+(Sym l _ _) `contentsElem` fs = l `elem` fs++-- Only remove objects from the list.+deleteContent :: Contents -> [String] -> [String]+deleteContent (Obj o _ _) fs = delete o fs+deleteContent _ fs = fs++----------------------------------------------------------------++qOwnRegex :: [String] -> IO ()+qOwnRegex args = mapM_ (qOwnRegex' pats) =<< allInstalledPackages+ where pats = map mkRegex args++qOwnRegex' :: [Regex] -> (String, String) -> IO ()+qOwnRegex' pats catname = readContents (putsRegex catname pats) contents ()+ where contents = contentsFromCatName catname++putsRegex :: (String, String) -> [Regex] -> Contents -> () -> IO (Bool, ())+putsRegex catname pats c _ = do+ when (c `regexElem` pats) match+ return (False, ())+ where match = putCatName catname >> putStr " (" >> putContents c>>putStrLn ")"++regexElem :: Contents -> [Regex] -> Bool+(Dir d) `regexElem` pats = mapMaybeOnce (flip matchRegex d) pats+(Obj o _ _) `regexElem` pats = mapMaybeOnce (flip matchRegex o) pats+(Sym l _ _) `regexElem` pats = mapMaybeOnce (flip matchRegex l) pats++mapMaybeOnce :: (a -> Maybe b) -> [a] -> Bool+mapMaybeOnce _ [] = False+mapMaybeOnce f (x:xs) =+ case f x of + Just _a -> True+ Nothing -> mapMaybeOnce f xs
+ Adelie/QSize.hs view
@@ -0,0 +1,61 @@+-- QSize.hs+--+-- Check the disk usage of an installed packaged.++module Adelie.QSize (qSize) where++import Directory (doesDirectoryExist)+import IO (try)+import Monad (mapM_, when)+import System.Posix.Files (fileSize, getFileStatus)+import System.Posix.Types (FileOffset)++import Adelie.Colour+import Adelie.Contents+import Adelie.Portage+import Adelie.Pretty++-- Size, Dir, Obj, Sym, Inaccessible+type Count = (FileOffset, Int, Int, Int, Int)++----------------------------------------------------------------++qSize :: [String] -> IO ()+qSize args = mapM_ size =<< findInstalledPackages args++size :: (String, String) -> IO ()+size catname = do+ putStr "Size of " >> putCatNameLn catname+ (size', dir, obj, sym, err) <- readContents count contents (0, 0, 0, 0, 0)+ putStr " Directories: " >> putNumLn dir+ putStr " Files: " >> putNumLn obj++ when (sym > 0) (putStr " Links: " >> putNumLn sym)+ when (err > 0) (putStr " Inaccessible: " >> putNumLn err)++ putStr " Total size: " >> putSizeLn size'+ putChar '\n'+ where contents = contentsFromCatName catname++----------------------------------------------------------------++count :: Contents -> Count -> IO (Bool, Count)++count (Dir d) (s,w,x,y,z) = do+ r <- doesDirectoryExist d+ if r+ then return (False, (s,w+1,x,y,z))+ else return (False, (s,w,x,y,z+1)) ++count (Obj o _ _) (s,w,x,y,z) = do+ r <- try (getFileStatus o)+ case r of+ Left _err -> return (False, (s, w, x, y, z+1))+ Right st -> return (False, (s+fileSize st, w, x+1, y, z))++count (Sym _ _ _) (s,w,x,y,z) = return (False, (s,w,x,y+1,z))++----------------------------------------------------------------++putSizeLn :: FileOffset -> IO ()+putSizeLn n = cyan >> putStr (show (n `div` 1024)) >> putStr " kb" >> off2
+ Adelie/QUse.hs view
@@ -0,0 +1,75 @@+-- QUse.hs+--+-- Module to describe the use flags of an installed package.++module Adelie.QUse (qUse) where++import Data.HashTable as HashTable+import Monad (mapM_, unless)++import Adelie.Colour+import Adelie.ListEx+import Adelie.Portage+import Adelie.Pretty+import Adelie.Use+import Adelie.UseDesc++----------------------------------------------------------------++qUse :: [String] -> IO ()+qUse args = qUse' =<< findInstalledPackages args++qUse' :: [(String, String)] -> IO ()+qUse' [] = return ()+qUse' catnames = do+ useDesc' <- readUseDesc+ useDescPackage' <- readUseDescPackage min' max'+ mapM_ (use useDesc' useDescPackage') catnames+ where min' = dropVersion $ fullnameFromCatName $ minimum catnames+ max' = dropVersion $ fullnameFromCatName $ maximum catnames++use :: UseDescriptions -> UseDescriptions -> (String, String) -> IO ()+use useDesc' useDescPackage' catname = do+ iUse <- readIUse fnIUse+ pUse <- readUse fnPUse+ let len = maximum $ map length iUse+ use' catname len useDesc' useDescPackage' iUse pUse+ where fnIUse = iUseFromCatName catname+ fnPUse = useFromCatName catname++use' :: (String, String) -> Int -> UseDescriptions -> UseDescriptions ->+ [String] -> [String] -> IO ()++use' catname _ _ _ [] _ = putStr "No USE flags for " >> putCatNameLn catname+use' catname len useDesc' useDescPackage' iUse pUse = do+ putStr "USE flags for " >> putCatNameLn catname+ mapM_ (format len useDesc' useDescPackage' pUse) iUse+ putChar '\n'++----------------------------------------------------------------++format :: Int -> UseDescriptions -> UseDescriptions ->+ [String] -> String -> IO ()++format len useDesc' useDescPackage' pUse iUse =+ inst >> putStr (pad len ' ' iUse) >> off >> putStr " : " >> desc+ where+ inst = if iUse `elem` pUse+ then putStr " + " >> red+ else putStr " " >> blue++ desc = do+ end <- desc' useDescPackage'+ unless end (do+ end' <- desc' useDesc'+ unless end' (putStrLn "<< no description >>"))++ desc' descs = do+ r <- HashTable.lookup descs iUse + case r of+ Just d -> puts d >> return True+ Nothing -> return False++puts :: String -> IO ()+puts d@('!':'!':_) = red >> putStr d >> off2+puts d = putStrLn d
+ Adelie/QWant.hs view
@@ -0,0 +1,26 @@+-- QWant.hs+--+-- List the direct dependencies of a file.++module Adelie.QWant (qWant) where++import Adelie.Depend+import Adelie.Portage+import Adelie.Pretty+import Adelie.Use++-------------------------------------------------------------++qWant :: [String] -> IO ()+qWant args = mapM_ qWant' =<< findInstalledPackages args++qWant' :: (String, String) -> IO ()+qWant' catname = do+ putStr "Dependencies for " >> putCatNameLn catname+ readUse fnIUse >>= readDepend fnDepend >>= mapM_ puts+ putChar '\n'+ where fnDepend = dependFromCatName catname+ fnIUse = useFromCatName catname++puts :: Dependency -> IO ()+puts a = putDependency a >> putChar '\n'
+ Adelie/Use.hs view
@@ -0,0 +1,34 @@+-- Use.hs+--+-- Module for parsing USE and IUSE, files, located in+-- portageDB/category/package/.++module Adelie.Use (+ useFromCatName,+ iUseFromCatName,+ readUse,+ readIUse+) where++import List (nub, sort)+import Monad (liftM)++import Adelie.Portage++----------------------------------------------------------------++useFromCatName :: (String, String) -> String+useFromCatName (cat, name) = concatPath [portageDB,cat,name,"USE"]++iUseFromCatName :: (String, String) -> String+iUseFromCatName (cat, name) = concatPath [portageDB,cat,name,"IUSE"]++----------------------------------------------------------------++readUse :: FilePath -> IO [String]+readUse fn = (liftM words $ readFile fn) `catch` (\ _ -> return [])++-- IUSE files sometimes have duplicate USE flags. I am not sure if it is the+-- intended behaviour, but I filter them out.+readIUse :: FilePath -> IO [String]+readIUse fn = (liftM (nub.sort.words) $ readFile fn) `catch` (\ _ -> return [])
+ Adelie/UseDesc.hs view
@@ -0,0 +1,86 @@+-- UseDesc.hs+--+-- Module for parsing portageProfile/use.desc and use.local.desc files.++module Adelie.UseDesc (+ UseDescriptions,+ readUseDesc,+ readUseDescPackage+) where++import Char (isSpace)+import Data.HashTable as HashTable+import Monad (when)++import Adelie.ListEx+import Adelie.Portage++type UseDescriptions = HashTable String String++----------------------------------------------------------------++readUseDesc :: IO UseDescriptions+readUseDesc = do+ table <- HashTable.new (==) hashString+ ls <- readFile useDesc+ mapM_ (useParser table) (lines ls)+ return table++useParser :: UseDescriptions -> String -> IO ()+useParser _ ('#':_) = return ()+useParser table line = insert table use desc+ where (use, desc) = myBreak line++myBreak :: String -> (String, String)+myBreak [] = ("", "")+myBreak (' ':'-':' ':xs) = ("", xs)+myBreak (x:xs) = (x:ys, zs)+ where (ys, zs) = myBreak xs++----------------------------------------------------------------++readUseDescPackage :: String -> String -> IO UseDescriptions+readUseDescPackage start end = do+ table <- HashTable.new (==) hashString+ ls <- readFile useDescPackage+ mapMUntil_ (useParser2 table start end) (lines ls)+ return table++mapMUntil_ :: Monad m => (a -> m Bool) -> [a] -> m ()+mapMUntil_ _ [] = return ()+mapMUntil_ f (x:xs) = do+ r <- f x+ when r (mapMUntil_ f xs)++useParser2 :: UseDescriptions -> String -> String -> String -> IO Bool+useParser2 _ _ _ [] = return True+useParser2 _ _ _ ('#':_) = return True+useParser2 table start end str = do+ case mid start catname end of+ LT -> return True+ EQ -> insert table use desc >> return True+ GT -> return False+ where str' = reverse $ dropWhile isSpace $ reverse str+ (catname, rest) = break2 (':' ==) str'+ (use, desc) = myBreak rest+ +----------------------------------------------------------------++-- In Haskell, vim-core > vim+-- In sort, vim-core < vim+-- Work around it.+myCompare :: String -> String -> Ordering+myCompare [] [] = EQ+myCompare _ [] = LT+myCompare [] _ = GT+myCompare (a:as) (b:bs) =+ if r == EQ+ then myCompare as bs + else r+ where r = compare a b++mid :: String -> String -> String -> Ordering+mid l m r+ | myCompare l m == GT = LT+ | myCompare m r == GT = GT+ | otherwise = EQ
+ Adelie/opts.c view
@@ -0,0 +1,13 @@+#include "opts.h"++static bool colour = true;++bool colour_enabled(void)+{+ return colour;+}++void set_colour_enabled(const bool on)+{+ colour = on;+}
+ Adelie/opts.h view
@@ -0,0 +1,9 @@+#ifndef __included_opts_h+#define __included_opts_h++#include <stdbool.h>++extern bool colour_enabled(void);+extern void set_colour_enabled(const bool on);++#endif
+ LICENCE.txt view
@@ -0,0 +1,23 @@++ Copyright (C) 2006 David Wang++ This software is provided 'as-is', without any express or implied+ warranty. In no event will the authors be held liable for any damages+ arising from the use of this software.++ Permission is granted to anyone to use this software for any purpose,+ including commercial applications, and to alter it and redistribute it+ freely, subject to the following restrictions:++ 1. The origin of this software must not be misrepresented; you must not+ claim that you wrote the original software. If you use this software+ in a product, an acknowledgment in the product documentation would be+ appreciated but is not required.++ 2. Altered source versions must be plainly marked as such, and must not+ be misrepresented as being the original software.++ 3. This notice may not be removed or altered from any source distribution.+++ [For informational purposes, this is the zlib licence.]
+ Main.hs view
@@ -0,0 +1,164 @@+-- Main.hs+--+-- Adelie is a collection of scripts to querying portage packages. ++module Main (main) where++import System (getArgs, getProgName)++import Adelie.Colour+import Adelie.Options+import Adelie.QChangelog+import Adelie.QCheck+import Adelie.QDepend+import Adelie.QHasUse+import Adelie.QList+import Adelie.QOwn+import Adelie.QSize+import Adelie.QUse+import Adelie.QWant++type CommandProc = [String] -> IO ()++data Command+ = Short String String CommandProc+ | Long String String String CommandProc++logCommands :: [Command]+logCommands = [+ (Long "c" "changes"+ "list changes since the installed version"+ qChangelog),+ (Short "cl"+ "find the changelog of a package"+ qLogFile)+ ]++listCommands :: [Command]+listCommands = [+ (Long "f" "files"+ "list the contents of a package"+ (qList ListAll)),+ (Short "fd"+ "list the directories in a package"+ (qList ListDirs)),+ (Short "ff"+ "list the files in a package"+ (qList ListFiles)),+ (Short "fl"+ "list the links in a package"+ (qList ListLinks))+ ]++ownCommands :: [Command]+ownCommands = [+ (Long "b" "belongs"+ "find the package(s) owning a file"+ qOwn),+ (Short "bp"+ "find the package(s) owning a file with regexp"+ qOwnRegex),+ (Long "s" "size"+ "find the size of files in a package"+ qSize),+ (Long "k" "check"+ "check MD5sums and timestamps of a package"+ qCheck)+ ]++dependCommands :: [Command]+dependCommands = [+ (Long "d" "depends"+ "list packages directly depending on this package"+ qDepend),+ (Short "dd"+ "list direct dependencies of a package"+ qWant)+ ]++useCommands :: [Command]+useCommands = [+ (Long "u" "uses"+ "describe a package's USE flags"+ qUse),+ (Long "h" "hasuse"+ "list all packages with a USE flag"+ qHasUse)+ ]++allCommands :: [Command]+allCommands = logCommands ++ listCommands ++ ownCommands ++ dependCommands ++ useCommands++----------------------------------------------------------------++main :: IO ()+main = do+ args0 <- getArgs+ let (options, commands) = span isOption args0+ mapM_ parseOptions options+ case commands of+ [] -> usage+ (cmd:cargs) -> (runCommand cmd allCommands) cargs+++isOption :: String -> Bool+isOption = ('-' ==) . head++----------------------------------------------------------------++parseOptions :: String -> IO ()+parseOptions [] = return ()++parseOptions "-C" = setColourEnabled False+parseOptions "--nocolor" = setColourEnabled False+parseOptions "--nocolour" = setColourEnabled False++parseOptions _ = return ()++----------------------------------------------------------------++runCommand :: String -> [Command] -> CommandProc+runCommand _ [] = (\ _ -> usage)++runCommand command ((Short cmd _ f):cs)+ | command == cmd = f+ | otherwise = runCommand command cs++runCommand command ((Long cmd0 cmd1 _ f):cs)+ | command == cmd0 = f+ | command == cmd1 = f+ | otherwise = runCommand command cs++----------------------------------------------------------------++usage :: IO ()+usage = do+ prog <- getProgName+ putStrLn "fquery 0.2\n"+ putStrLn $ "Usage: " ++ prog ++ " [options] <command> <arguments>\n"++ cyan >> putStr "Options:" >> off2+ inYellow (putStr " -C --nocolour") >> tab >> putStrLn "turn off colours"+ nl++ cyan >> putStr "Commands for Installed Packages:" >> off2+ mapM_ putCommand logCommands; nl+ mapM_ putCommand listCommands; nl+ mapM_ putCommand ownCommands; nl+ mapM_ putCommand dependCommands; nl+ mapM_ putCommand useCommands; nl++putCommand :: Command -> IO ()+putCommand (Short cmd desc _) = f `withDesc` desc+ where f = green >> putStr cmd >> off >> tab++putCommand (Long cmd0 cmd1 desc _) = f `withDesc` desc+ where f = green >> putStr (cmd0 ++ " " ++ cmd1) >> off++withDesc :: IO () -> String -> IO ()+f `withDesc` desc = putStr " " >> f >> tab >> putStrLn desc++tab :: IO ()+tab = putChar '\t'+nl :: IO ()+nl = putChar '\n'
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMainWithHooks autoconfUserHooks
+ TODO view
@@ -0,0 +1,4 @@+ * make fquery a drop-in replacement of equery:+ o outpout compatible+ o options full+ * explore attoparsec in search of faster performance
+ configure view
@@ -0,0 +1,23 @@+#!/bin/sh+#+# Fake configure script.++portageq=/usr/bin/portageq++PORTAGE_TREE=`${portageq} portdir 2>/dev/null`+PORTAGE_DB=`${portageq} vdb_path 2>/dev/null`++if [ -z $PORTAGE_TREE ]; then+ PORTAGE_TREE="/usr/portage"+fi++if [ -z $PORTAGE_DB ]; then+ PORTAGE_DB="/var/db/pkg"+fi++echo "portdir: ${PORTAGE_TREE}"+echo "vdb_path: ${PORTAGE_DB}"++sed -e s,'@@PortageTree@@',"\"${PORTAGE_TREE}\"", \+ -e s,'@@PortageDB@@',"\"${PORTAGE_DB}\"", \+ "Adelie/Config.hs.in" > "Adelie/Config.hs"
+ fquery.cabal view
@@ -0,0 +1,53 @@+Name: fquery+Version: 0.2.1++Author: David Wang <millimillenary@gmail.com>, Sergei Trofimovich <slyfox@inbox.ru>+Maintainer: Sergei Trofimovich <slyfox@inbox.ru>+Copyright: 2006 David Wang, 2009 Sergei Trofimovich++License-File: LICENCE.txt+License: OtherLicense++Synopsis: Installed package query tool for Gentoo Linux+Description: Installed package query tool for Gentoo Linux++ Home page http://home.exetel.com.au/tjaden/fquery/+ Public repository is http://repo.or.cz/w/fquery.git++Category: Gentoo++Build-Type: Configure+Build-Depends: base, haskell98, parsec, unix, regex-compat, process, directory+Extra-Source-Files:+ configure+ Adelie/Config.hs.in+ Adelie/opts.h+ TODO++Executable: fquery+Main-is: Main.hs+Other-Modules: Adelie.Colour+ Adelie.CompareVersion+ Adelie.Contents+ Adelie.Depend+ Adelie.ListEx+ Adelie.Options+ Adelie.Portage+ Adelie.Pretty+ Adelie.Provide+ Adelie.QChangelog+ Adelie.QCheck+ Adelie.QDepend+ Adelie.QHasUse+ Adelie.QList+ Adelie.QOwn+ Adelie.QSize+ Adelie.QUse+ Adelie.QWant+ Adelie.Use+ Adelie.UseDesc++GHC-Options: -O2 -Wall+-- GHC-Options: -Werror++c-sources: Adelie/opts.c