cblrepo 0.3.1 → 0.4.0
raw patch · 12 files changed
+243/−179 lines, 12 files
Files
- cblrepo.cabal +4/−4
- src/Add.hs +3/−2
- src/IdxSync.hs +0/−28
- src/IdxVersion.hs +0/−56
- src/ListPkgs.hs +2/−2
- src/Main.hs +18/−10
- src/PkgBuild.hs +31/−40
- src/Remove.hs +47/−0
- src/Sync.hs +28/−0
- src/Util/Misc.hs +38/−19
- src/Util/Translation.hs +16/−18
- src/Versions.hs +56/−0
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