packages feed

cabal-install-0.4.0: Hackage/Index.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Hackage.Index
-- Copyright   :  (c) David Himmelstrup 2005, Bjorn Bringert 2007
-- License     :  BSD-like
--
-- Maintainer  :  lemmih@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
-- Reading the local package index.
-----------------------------------------------------------------------------
module Hackage.Index (getKnownPackages) where

import Hackage.Config
import Hackage.Types
import Hackage.Tar

import Prelude hiding (catch)
import Control.Exception (catch, Exception(IOException))
import qualified Data.ByteString.Lazy.Char8 as BS
import Data.ByteString.Lazy.Char8 (ByteString)
import System.FilePath ((</>), takeExtension, splitDirectories, normalise)
import System.IO (hPutStrLn, stderr)
import System.IO.Error (isDoesNotExistError)

import Distribution.PackageDescription (parsePackageDescription, ParseResult(..))
import Distribution.Package (PackageIdentifier(..))
import Distribution.Version (readVersion)

getKnownPackages :: ConfigFlags -> IO [PkgInfo]
getKnownPackages cfg
    = fmap concat $ mapM (readRepoIndex cfg) $ configRepos cfg

readRepoIndex :: ConfigFlags -> Repo -> IO [PkgInfo]
readRepoIndex cfg repo =
    do let indexFile = repoCacheDir cfg repo </> "00-index.tar"
       fmap (parseRepoIndex repo) (BS.readFile indexFile)
          `catch` (\e -> do case e of
                              IOException ioe | isDoesNotExistError ioe ->
                                hPutStrLn stderr "The package list does not exist. Run 'cabal update' to download it."
                              _ -> hPutStrLn stderr ("Error: " ++ show e)
                            return [])

parseRepoIndex :: Repo -> ByteString -> [PkgInfo]
parseRepoIndex repo s =
    do (hdr, content) <- readTarArchive s
       if takeExtension (tarFileName hdr) == ".cabal"
         then case splitDirectories (normalise (tarFileName hdr)) of
                [pkgname,vers,_] ->
                  let descr = case parsePackageDescription (BS.unpack content) of
                        ParseOk _ d -> d
                        _           -> error $ "Couldn't read cabal file "
                                            ++ show (tarFileName hdr)
                   in case readVersion vers of
                        Just ver ->
                         return $ PkgInfo {
                                 pkgInfoId = PackageIdentifier pkgname ver,
                                 pkgRepo = repo,
                                 pkgDesc = descr
                               }
                        _ -> []
                _ -> []
         else []