packages feed

cblrepo 0.3.1 → 0.4.0

raw patch · 12 files changed

+243/−179 lines, 12 files

Files

cblrepo.cabal view
@@ -1,5 +1,5 @@ name: cblrepo-version: 0.3.1+version: 0.4.0 cabal-version: >= 1.6 license: OtherLicense license-file: LICENSE-2.0@@ -26,9 +26,9 @@ executable cblrepo     hs-source-dirs: src     main-is: Main.hs-    other-modules: Util.Misc PkgDB Add BumpPkgs BuildPkgs IdxSync-        IdxVersion Updates ListPkgs Urls PkgBuild Util.Translation-        OldPkgDB ConvertDB+    other-modules: Util.Misc PkgDB Add BumpPkgs BuildPkgs Sync+        Versions Updates ListPkgs Urls PkgBuild Util.Translation+        OldPkgDB ConvertDB Remove     build-depends: base ==4.3.*, cmdargs ==0.7.*, filepath ==1.2.*,         directory ==1.1.*, Cabal ==1.10.*, json ==0.4.*,         bytestring ==0.9.*, tar ==0.3.*, zlib ==0.5.*, mtl ==2.0.*,
src/Add.hs view
@@ -29,6 +29,7 @@ import Control.Monad import Control.Monad.Error import Control.Monad.Reader+import Data.Either import Data.List import Data.Maybe import Data.Version@@ -121,9 +122,9 @@     pD <- cfgGet patchDir     cbls <- cfgGet cbls     dR <- cfgGet dryRun-    genPkgs <- liftIO $ mapM (\ c -> withTemporaryDirectory "/tmp/cblrepo." (readCabal pD c)) cbls+    genPkgs <- mapM (\ c -> runErrorT $ withTempDirErrT "/tmp/cblrepo." (\ d -> readCabal pD c d)) cbls >>= exitOnErrors     let pkgNames = map ((\ (P.PackageName n) -> n ) . P.pkgName . package . packageDescription) genPkgs-    liftIO $ when (or . catMaybes $ map (liftM isBasePkg . lookupPkg db) pkgNames) (putStrLn "Trying to add a base pkg!!" >> exitFailure)+    exitOnErrors $ map (Left . (++) "Trying to add base package: ") (filter (maybe False isBasePkg . lookupPkg db) pkgNames)     let tmpDb = filter (\ p -> not $ pkgName p `elem` pkgNames) db     case doAddRepo tmpDb genPkgs of         Left (unSats, brksOthrs) -> liftIO (mapM_ printUnSat unSats >> mapM_ printBrksOth brksOthrs)
− src/IdxSync.hs
@@ -1,28 +0,0 @@-{-- - Copyright 2011 Per Magnus Therning- -- - Licensed under the Apache License, Version 2.0 (the "License");- - you may not use this file except in compliance with the License.- - You may obtain a copy of the License at- -- -     http://www.apache.org/licenses/LICENSE-2.0- -- - Unless required by applicable law or agreed to in writing, software- - distributed under the License is distributed on an "AS IS" BASIS,- - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.- - See the License for the specific language governing permissions and- - limitations under the License.- -}--module IdxSync where--import Util.Misc--import Control.Monad.Reader-import System.FilePath-import Control.Monad.Error--idxSync :: ReaderT Cmds IO ()-idxSync = do-    aD <- cfgGet appDir-    liftIO $ getFromURL "http://hackage.haskell.org/packages/archive/00-index.tar.gz" (aD </> "00-index.tar.gz")
− src/IdxVersion.hs
@@ -1,56 +0,0 @@-{-- - Copyright 2011 Per Magnus Therning- -- - Licensed under the Apache License, Version 2.0 (the "License");- - you may not use this file except in compliance with the License.- - You may obtain a copy of the License at- -- -     http://www.apache.org/licenses/LICENSE-2.0- -- - Unless required by applicable law or agreed to in writing, software- - distributed under the License is distributed on an "AS IS" BASIS,- - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.- - See the License for the specific language governing permissions and- - limitations under the License.- -}--module IdxVersion where--import Util.Misc--import Codec.Archive.Tar as Tar-import Codec.Compression.GZip as GZip-import Control.Monad-import Control.Monad.Reader-import Data.List-import Data.Maybe-import Distribution.Text-import Distribution.Version-import System.FilePath-import qualified Data.ByteString.Lazy.Char8 as BS--idxVersion :: ReaderT Cmds IO ()-idxVersion = do-    aD <- cfgGet appDir-    pkgs <- cfgGet pkgs-    liftIO $ do-        es <- liftM (Tar.read . GZip.decompress) (BS.readFile $ aD </> "00-index.tar.gz")-        mapM_ (printVersions . findVersions es) pkgs--findVersions es p = (p, findV p es [])-    where-        findV pkgName (Next e es) acc = let-                eP = entryPath e-                (ePkg:v:_) = splitDirectories eP-            in if ('/' `elem` eP) && (pkgName == ePkg)-                then findV pkgName es (v:acc)-                else findV pkgName es acc--        findV _ Done acc = let-                vs :: [Version]-                vs = map (fromJust . simpleParse) acc-            in map display $ sort vs--printVersions (p, vs) = do-    putStr $ p ++ " : "-    putStrLn $ unwords vs
src/ListPkgs.hs view
@@ -27,9 +27,9 @@  listPkgs :: ReaderT Cmds IO () listPkgs = do-    iB <- cfgGet incBase+    lA <- cfgGet listAll     db <- cfgGet dbFile >>= liftIO . readDb-    let pkgs = if not iB+    let pkgs = if not lA             then filter (not . isBasePkg) db             else db     liftIO $ mapM_ printCblPkgShort pkgs
src/Main.hs view
@@ -19,14 +19,15 @@ import Add import BuildPkgs import BumpPkgs-import IdxSync-import IdxVersion+import Sync+import Versions import ListPkgs import Updates import Util.Misc import Urls import PkgBuild import ConvertDB+import Remove  import Paths_cblrepo @@ -72,18 +73,18 @@     , pkgs := def += args += typ "PKG"     ] += name "build" += help "list packages that need rebuilding, in order" -cmdIdxSync = record defIdxSync [ argAppDir ] += help "update the index"+cmdSync = record defSync [ argAppDir ] += name "sync" += help "update the index" -cmdIdxVersion = record defIdxVersion+cmdVersions = record defVersions     [ argAppDir     , pkgs := def += args += typ "PKG"-    ] += help "list available versions"+    ] += name "versions" += help "list available versions"  cmdUpdates = record defUpdates [ argAppDir , argDbFile ] += name "updates" += help "check for availabale updates"  cmdListPkgs = record defListPkgs     [ argAppDir, argDbFile-    , incBase := False += help "include base packages in listing"+    , listAll := False += name "a" += explicit += help "list all packages"     ] += name "list" += help "list packages in repo"  cmdUrls = record defUrls@@ -104,17 +105,23 @@     , outDbFile := "new-cblrepo.db" += explicit += name "o" += name "outdb" += typFile += help "new database"     ] += help "convert an old database to the new format" +cmdRemovePkg = record defRemovePkg+    [ argAppDir, argDbFile, argDryRun+    , pkgs := def += args += typ "PKG"+    ] += name "rm" += help "remove packages"+ cmds = cmdArgsMode_ $ modes_     [ cmdAddPkg     , cmdBuildPkgs     , cmdBumpPkgs-    , cmdIdxSync-    , cmdIdxVersion+    , cmdSync+    , cmdVersions     , cmdListPkgs     , cmdUpdates     , cmdUrls     , cmdPkgBuild     , cmdConvertDb+    , cmdRemovePkg     ]     += program progName     += summary (progName ++ " v" ++ (display version))@@ -131,10 +138,11 @@             CmdAdd {} -> runReaderT add c'             BuildPkgs {} -> runReaderT buildPkgs c'             BumpPkgs {} -> runReaderT bumpPkgs c'-            IdxSync {} -> runReaderT idxSync c'-            IdxVersion {} -> runReaderT idxVersion c'+            Sync {} -> runReaderT sync c'+            Versions {} -> runReaderT versions c'             ListPkgs {} -> runReaderT listPkgs c'             Updates {} -> runReaderT updates c'             Urls {} -> runReaderT urls c'             PkgBuild {} -> runReaderT pkgBuild c'             ConvertDb {} -> runReaderT convertDb c'+            RemovePkg {} -> runReaderT remove c'
src/PkgBuild.hs view
@@ -20,55 +20,46 @@ import Util.Misc import Util.Translation +import Control.Monad.Error import Control.Monad.Reader+import Data.Either import Data.Maybe import Distribution.Text-import System.Exit-import System.Unix.Directory import System.Directory-import System.IO(openFile)+import System.Exit import System.IO+import System.Unix.Directory import Text.PrettyPrint.ANSI.Leijen +pkgBuild :: ReaderT Cmds IO ()+pkgBuild = do+    db <- cfgGet dbFile >>= liftIO . readDb+    pD <- cfgGet patchDir+    pkgs <- cfgGet pkgs+    mapM (runErrorT . generatePkgBuild db pD) pkgs >>= exitOnErrors >> return ()+ -- TODO: --  - patches:---      .cabal patch - put into sources array, copied into package dir---      PKGBUILD patch - applied --      build patch - put into source array, copied into package dir --  - flags-pkgBuild :: ReaderT Cmds IO ()-pkgBuild = let-        failFinalize _ = error "pkgBuild: unexpected failure to finalize a package"+-- generatePkgBuild :: CblDB -> String -> String -> ErrorT String IO ()+generatePkgBuild db patchDir pkg = let+        appendPkgVer = pkg ++ "," ++ (display $ pkgVersion $ fromJust $ lookupPkg db pkg)     in do-        db <- cfgGet dbFile >>= liftIO . readDb-        pD <- cfgGet patchDir-        pkgs <- cfgGet pkgs-        unless (all isJust (map (lookupPkg db) pkgs)) $-            liftIO (mapM_ (printNotAPkg db) pkgs >> exitFailure)-        let cbls = map (appendPkgVer db) pkgs-        genPDs <- liftIO $ mapM (\ c -> withTemporaryDirectory "/tmp/cblrepo." (readCabal pD c)) cbls-        let pds = map (either failFinalize id . finalizePkg db) genPDs-        let aps = map (translate db . fst) pds-        apsP <- liftIO $ mapM (addPatches pD) aps-        apsF <- liftIO $ mapM (\ a -> withTemporaryDirectory "/tmp/cblrepo." (addHashes a)) apsP-        liftIO $ mapM_ (\ a -> createDirectoryIfMissing False (apPkgName a)) apsF-        liftIO $ mapM_ (\ a -> withWorkingDirectory (apPkgName a) $ do-            copyPatches "." a-            hF <- openFile "PKGBUILD" WriteMode -            hPutDoc hF $ pretty a-            hClose hF-            maybe (return ()) (\ pfn -> applyPatch "PKGBUILD" pfn) (apPkgbuildPatch a)-            when (apHasLibrary a) $ do-                hFI <- openFile (apPkgName a ++ ".install") WriteMode-                let ai = aiFromAP a-                hPutDoc hFI $ pretty ai-                hClose hFI-            ) apsF--printNotAPkg db pkg = maybe doPrint (const $ return ()) (lookupPkg db pkg)-    where-        doPrint = putStrLn $ "Unknown package: " ++ pkg--appendPkgVer db pkg = let-        displayVer = display . pkgVersion . fromJust . lookupPkg db-    in pkg ++ "," ++ (displayVer pkg)+        maybe (throwError $ "Unknown package: " ++ pkg) (const $ return ()) (lookupPkg db pkg)+        genericPkgDesc <- withTempDirErrT "/tmp/cblrepo." (readCabal patchDir appendPkgVer)+        pkgDesc <- either (const $ throwError ("Failed to finalize package: " ++ pkg)) (return . fst) (finalizePkg db genericPkgDesc)+        let archPkg = translate db pkgDesc+        archPkgWHash <- withTempDirErrT "/tmp/cblrepo." (addHashes archPkg)+        liftIO $ createDirectoryIfMissing False (apPkgName archPkgWHash)+        liftIO $ withWorkingDirectory (apPkgName archPkgWHash) $ do+            copyPatches "." archPkgWHash+            hPKGBUILD <- openFile "PKGBUILD" WriteMode+            hPutDoc hPKGBUILD $ pretty archPkgWHash+            hClose hPKGBUILD+            maybe (return ()) (\ pfn -> (runErrorT $ applyPatch "PKGBUILD" pfn) >> return ()) (apPkgbuildPatch archPkgWHash)+            when (apHasLibrary archPkgWHash) $ do+                hInstall <- openFile (apPkgName archPkgWHash ++ ".install") WriteMode+                let archInstall = aiFromAP archPkgWHash+                hPutDoc hInstall $ pretty archInstall+                hClose hInstall
+ src/Remove.hs view
@@ -0,0 +1,47 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ -     http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Remove where++-- {{{1 imports+-- {{{1 local+import PkgDB+import Util.Misc++-- {{{1 system+import Control.Monad.Error+import Control.Monad.Reader+import System.Exit++-- {{{1 remove+remove :: ReaderT Cmds IO ()+remove = do+    dbFn <- cfgGet dbFile+    db <- liftIO $ readDb dbFn+    pkgs <- cfgGet pkgs+    dR <- cfgGet dryRun+    liftIO $ either+        (\ s -> putStrLn s >> exitFailure)+        (\ newDb -> unless dR $ saveDb newDb dbFn)+        (foldM removeOne db pkgs)++removeOne :: CblDB -> String -> Either String CblDB+removeOne db pkg = let+        deps = tail $ transitiveDependants db [pkg]+        depsString = foldr (\ s t -> "  " ++ s ++ "\n" ++ t) "" deps+    in if null deps+        then return (delPkg db pkg)+        else throwError ("Can't delete package " ++ pkg ++ ", dependants:\n" ++ depsString)
+ src/Sync.hs view
@@ -0,0 +1,28 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ -     http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Sync where++import Util.Misc++import Control.Monad.Reader+import System.FilePath+import Control.Monad.Error++sync :: ReaderT Cmds IO ()+sync = do+    aD <- cfgGet appDir+    liftIO $ getFromURL "http://hackage.haskell.org/packages/archive/00-index.tar.gz" (aD </> "00-index.tar.gz")
src/Util/Misc.hs view
@@ -26,6 +26,7 @@ import Control.Monad.Error import Control.Monad.Reader import Data.Data+import Data.Either import Data.List import Data.Typeable import Distribution.Compiler@@ -43,6 +44,7 @@ import System.IO import System.Posix.Files import System.Process+import System.Unix.Directory import qualified Control.Exception as CE import qualified Data.ByteString.Lazy.Char8 as BS @@ -71,25 +73,27 @@     = CmdAdd { appDir :: FilePath, dbFile :: FilePath, patchDir :: FilePath, dryRun :: Bool, pkgType :: PkgType, cbls :: [FilePath] }     | BuildPkgs { appDir :: FilePath, dbFile :: FilePath, pkgs :: [String] }     | BumpPkgs { appDir :: FilePath, dbFile :: FilePath, dryRun :: Bool, inclusive :: Bool, pkgs :: [String] }-    | IdxSync { appDir :: FilePath }-    | IdxVersion { appDir :: FilePath, pkgs :: [String] }-    | ListPkgs { appDir :: FilePath, dbFile :: FilePath, incBase :: Bool }+    | Sync { appDir :: FilePath }+    | Versions { appDir :: FilePath, pkgs :: [String] }+    | ListPkgs { appDir :: FilePath, dbFile :: FilePath, listAll :: Bool }     | Updates { appDir :: FilePath, dbFile :: FilePath }     | Urls { appDir :: FilePath, pkgVers :: [(String, String)] }     | PkgBuild { appDir :: FilePath, dbFile :: FilePath, patchDir :: FilePath, pkgs :: [String] }     | ConvertDb { appDir :: FilePath, inDbFile :: FilePath, outDbFile :: FilePath }+    | RemovePkg { appDir :: FilePath, dbFile :: FilePath, dryRun :: Bool, pkgs :: [String] }     deriving (Show, Data, Typeable)  defCmdAdd = CmdAdd "" "" "" True RepoPkgT [] defBuildPkgs =  BuildPkgs "" "" [] defBumpPkgs =  BumpPkgs "" "" False False []-defIdxSync =  IdxSync ""-defIdxVersion =  IdxVersion "" []-defListPkgs =  ListPkgs "" "" True+defSync =  Sync ""+defVersions =  Versions "" []+defListPkgs =  ListPkgs "" "" False defUpdates =  Updates "" "" defUrls =  Urls "" [] defPkgBuild =  PkgBuild "" "" "" [] defConvertDb = ConvertDb "" "" ""+defRemovePkg = RemovePkg "" "" False []  cfgGet f = liftM f ask @@ -105,20 +109,21 @@  -- {{{1 applyPatchIfExist applyPatch origFilename patchFilename = do-    (ec, _, err) <- readProcessWithExitCode "patch" [origFilename, patchFilename] ""+    (ec, _, err) <- liftIO $ readProcessWithExitCode "patch" [origFilename, patchFilename] ""     case ec of         ExitSuccess -> return ()         ExitFailure _ ->-            hPutStrLn stderr ("Failed patching " ++ origFilename ++ " with " ++ patchFilename) >> exitFailure+            throwError ("Failed patching " ++ origFilename ++ " with " ++ patchFilename)  applyPatchIfExist origFilename patchFilename =-    fileExist patchFilename >>= flip when (applyPatch origFilename patchFilename)+    (liftIO $ fileExist patchFilename) >>= flip when (applyPatch origFilename patchFilename)  -- {{{1 package descriptions -- {{{2 readCabal data LocType = Url | Idx | File  -- | Read in a Cabal file.+readCabal :: FilePath -> String -> FilePath -> ErrorT String IO GenericPackageDescription readCabal patchDir loc tmpDir = let         locType             | isInfixOf "://" loc = Url@@ -150,16 +155,16 @@                         _ -> Nothing              in do-                fp <- getAppUserDataDirectory "cblrepo"+                fp <- liftIO $ getAppUserDataDirectory "cblrepo"                 es <- liftM (Tar.read . GZip.decompress)-                    (BS.readFile $ fp </> "00-index.tar.gz")-                e <- maybe (error $ "No entry for " ++ pkgStr)+                    (liftIO $ BS.readFile $ fp </> "00-index.tar.gz")+                e <- maybe (throwError $ "No entry for " ++ pkgStr)                     return                     (esFindEntry path es)-                cbl <- maybe (error $ "Failed to extract contents for " ++ pkgStr)+                cbl <- maybe (throwError $ "Failed to extract contents for " ++ pkgStr)                     return                     (eGetContent e)-                writeFile fn cbl+                liftIO $ writeFile fn cbl                 return fn          extractName fn = liftM name $ readPackageDescription silent fn@@ -169,14 +174,13 @@      in do         cblFn <- case locType of-            File -> copyCabal tmpDir loc+            File -> liftIO $ copyCabal tmpDir loc             Idx -> extractCabal tmpDir loc-            Url -> downloadCabal tmpDir loc-        pn <- extractName cblFn+            Url -> liftIO $ downloadCabal tmpDir loc+        pn <- liftIO $ extractName cblFn         let patchFn = patchDir </> pn <.> "cabal"-        return patchFn         applyPatchIfExist cblFn patchFn-        readPackageDescription silent cblFn+        liftIO $ readPackageDescription silent cblFn  -- {{{2 finalising finalizePkg db = finalizePackageDescription@@ -205,3 +209,18 @@         return (if cE then Just cblPatch else Nothing,             if pE then Just pkgPatch else Nothing,             if bE then Just bldPatch else Nothing)++-- {{{1 ErrorT+reWrapErrT (Left e) = throwError e+reWrapErrT (Right v) = return v++withTempDirErrT fp func = do+    r <- liftIO $ withTemporaryDirectory fp (\ p -> runErrorT $ func p)+    reWrapErrT r++exitOnErrors vs = let+        es = lefts vs+    in+        if (not $ null $ lefts vs)+            then liftIO $ mapM_ (hPutStrLn stderr) es >> exitFailure+            else return (rights vs)
src/Util/Translation.hs view
@@ -25,22 +25,23 @@ import PkgDB as DB import Util.Misc +import Control.Monad+import Control.Monad.Error+import Data.Char+import Data.List+import Data.Maybe import Data.Monoid-import Text.PrettyPrint.ANSI.Leijen hiding((</>)) import Data.Version-import Distribution.Text import Distribution.Package as P-import Data.Char import Distribution.PackageDescription-import Data.Maybe-import System.FilePath-import System.Unix.Directory+import Distribution.Text+import System.Directory import System.Exit+import System.FilePath import System.IO import System.Process-import Data.List-import System.Directory-import Control.Monad+import System.Unix.Directory+import Text.PrettyPrint.ANSI.Leijen hiding((</>))  -- {{{1 ShQuotedString newtype ShQuotedString = ShQuotedString String@@ -349,22 +350,19 @@     in maybe (return ()) (\ fn -> copyFile fn (destDir </> "cabal.patch")) cabalPatch  -- {{{1 addHashes--- TODO:---  • deal with errors better addHashes ap tmpDir = let         hashes = map (filter (`elem` "1234567890abcdef")) . lines . drop 11         pkgbuildFn = tmpDir </> "PKGBUILD"         pkgbuildPatch = apPkgbuildPatch ap     in do-        copyPatches tmpDir ap-        writeFile pkgbuildFn (show $ pretty ap)-        maybe (return ()) (\ pfn -> applyPatch pkgbuildFn pfn) pkgbuildPatch-        (ec, out, er) <- withWorkingDirectory tmpDir (readProcessWithExitCode "makepkg" ["-g"] "")+        liftIO $ copyPatches tmpDir ap+        liftIO $ writeFile pkgbuildFn (show $ pretty ap)+        maybe (return ()) (\ pfn -> (applyPatch pkgbuildFn pfn) >> return ()) pkgbuildPatch+        (ec, out, er) <- liftIO $ withWorkingDirectory tmpDir (readProcessWithExitCode "makepkg" ["-g"] "")         case ec of             ExitFailure _ -> do-                hPutStrLn stderr er-                hPutStrLn stderr "makepkg: error while calculating the source hashes"-                return ap+                -- hPutStrLn stderr er+                throwError $ "makepkg: error while calculating the source hashes for " ++ (apHkgName ap)             ExitSuccess -> do                 if "sha256sums=(" `isPrefixOf` out                     then return ap { apShSha256Sums = shVarNewValue (apShSha256Sums ap) (ShArray $ hashes out) }
+ src/Versions.hs view
@@ -0,0 +1,56 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ -     http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Versions where++import Util.Misc++import Codec.Archive.Tar as Tar+import Codec.Compression.GZip as GZip+import Control.Monad+import Control.Monad.Reader+import Data.List+import Data.Maybe+import Distribution.Text+import Distribution.Version+import System.FilePath+import qualified Data.ByteString.Lazy.Char8 as BS++versions :: ReaderT Cmds IO ()+versions = do+    aD <- cfgGet appDir+    pkgs <- cfgGet pkgs+    liftIO $ do+        es <- liftM (Tar.read . GZip.decompress) (BS.readFile $ aD </> "00-index.tar.gz")+        mapM_ (printVersions . findVersions es) pkgs++findVersions es p = (p, findV p es [])+    where+        findV pkgName (Next e es) acc = let+                eP = entryPath e+                (ePkg:v:_) = splitDirectories eP+            in if ('/' `elem` eP) && (pkgName == ePkg)+                then findV pkgName es (v:acc)+                else findV pkgName es acc++        findV _ Done acc = let+                vs :: [Version]+                vs = map (fromJust . simpleParse) acc+            in map display $ sort vs++printVersions (p, vs) = do+    putStr $ p ++ " : "+    putStrLn $ unwords vs