packages feed

full-text-search-0.2.1.0: demo/PackageIndexUtils.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Client.IndexUtils
-- Copyright   :  (c) Duncan Coutts 2008
-- License     :  BSD-like
--
-- Maintainer  :  duncan@community.haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
-- Extra utils related to the package indexes.
-----------------------------------------------------------------------------
module PackageIndexUtils (
    readPackageIndexFile
  ) where

import qualified Codec.Archive.Tar as Tar

import Distribution.Package
         ( PackageId, PackageIdentifier(..), PackageName(..) )
import Distribution.PackageDescription
         ( GenericPackageDescription )
import Distribution.PackageDescription.Parse
         ( parsePackageDescription )
import Distribution.ParseUtils
         ( ParseResult(..) )
import Distribution.Text
         ( simpleParse )
import Distribution.Simple.Utils
         ( fromUTF8 )

import Data.Maybe (fromMaybe)
import qualified Data.ByteString.Lazy as BS
import qualified Data.ByteString.Lazy.Char8 as BS.Char8
import Data.ByteString.Lazy (ByteString)
import System.FilePath (takeExtension, splitDirectories, normalise)


readPackageIndexFile :: FilePath -> IO [(PackageId, GenericPackageDescription)]
readPackageIndexFile indexFile =
      either fail return
    . parsePackageIndex
  =<< BS.readFile indexFile

-- | Parse an uncompressed \"00-index.tar\" repository index file represented
-- as a 'ByteString'.
--
parsePackageIndex :: ByteString
                  -> Either String [(PackageId, GenericPackageDescription)]
parsePackageIndex = accum [] . Tar.read
  where
    accum pkgs es = case es of
      Tar.Fail err   -> Left  (show err)
      Tar.Done       -> Right (reverse pkgs)
      Tar.Next e es' -> accum pkgs' es'
        where
          pkgs' = extract pkgs e

    extract pkgs entry =
       fromMaybe pkgs $ tryExtractPkg
      where
        tryExtractPkg = do
          (pkgid, pkg) <- extractPkg entry
          return ((pkgid, pkg):pkgs)


extractPkg :: Tar.Entry -> Maybe (PackageId, GenericPackageDescription)
extractPkg entry = case Tar.entryContent entry of
  Tar.NormalFile content _
     | takeExtension fileName == ".cabal"
    -> case splitDirectories (normalise fileName) of
        [pkgname,vers,_] -> case simpleParse vers of
          Just ver -> Just (pkgid, descr)
            where
              pkgid  = PackageIdentifier (PackageName pkgname) ver
              parsed = parsePackageDescription . fromUTF8 . BS.Char8.unpack
                                               $ content
              descr  = case parsed of
                ParseOk _ d -> d
                _           -> error $ "Couldn't read cabal file "
                                    ++ show fileName
          _ -> Nothing
        _ -> Nothing
  _ -> Nothing
  where
    fileName = Tar.entryPath entry