hackage-db-1.11: src/Distribution/Hackage/DB/Parsed.hs
{- |
Module : Distribution.Hackage.DB.Parsed
License : BSD3
Maintainer : simons@cryp.to
Stability : provisional
Portability : portable
This module provides simple access to the Hackage database by means
of 'Map'.
-}
module Distribution.Hackage.DB.Parsed
( Hackage, readHackage, readHackage', parseHackage
, parseUnparsedHackage
, parsePackage, parsePackage'
)
where
import qualified Data.ByteString.Lazy as BSC ( unpack )
import Data.ByteString.Lazy.Char8 ( ByteString )
import Data.Map
import Data.String.UTF8 ( toString, fromRep )
import Data.Version
import qualified Distribution.Hackage.DB.Unparsed as Unparsed
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
import Distribution.Text ( display )
-- | A 'Map' representation of the Hackage database. Every package name
-- maps to a non-empty set of version, and for every version there is a
-- parsed Cabal file.
type Hackage = Map String (Map Version GenericPackageDescription)
-- | Read the Hackage database from the location determined by 'hackagePath'
-- and return a 'Map' that provides fast access to its contents.
readHackage :: IO Hackage
readHackage = fmap parseUnparsedHackage Unparsed.readHackage
-- | Read the Hackage database from the given 'FilePath' and return a
-- 'Hackage' map that provides fast access to its contents.
readHackage' :: FilePath -> IO Hackage
readHackage' = fmap parseUnparsedHackage . Unparsed.readHackage'
-- | Parse the contents of Hackage's @00-index.tar@ into a 'Hackage' map.
parseHackage :: ByteString -> Hackage
parseHackage = parseUnparsedHackage . Unparsed.parseHackage
-- | Convert an 'Unparsed.Hackage' map into a parsed 'Hackage' map.
parseUnparsedHackage :: Unparsed.Hackage -> Hackage
parseUnparsedHackage = Data.Map.mapWithKey parsePackages
where
parsePackages :: String -> Map Version ByteString -> Map Version GenericPackageDescription
parsePackages name = Data.Map.mapWithKey (parsePackage name)
-- | Convenience wrapper around 'parsePackage'' to parse a single Cabal
-- file. Failure is reported with 'error'.
parsePackage :: String -> Version -> ByteString -> GenericPackageDescription
parsePackage name version buf = case parsePackage' buf of
Right a -> a
Left err -> error $ "cannot parse cabal package " ++ show name ++ "-" ++ display version ++ ": " ++ err
-- | Parse a single Cabal file.
parsePackage' :: ByteString -> Either String GenericPackageDescription
parsePackage' buf = case parsePackageDescription (decodeUTF8 buf) of
ParseOk _ a -> Right a
ParseFailed err -> Left (show err)
where
decodeUTF8 :: ByteString -> String
decodeUTF8 = toString . fromRep . BSC.unpack