module Distribution.Hackage.DB
( Hackage, readHackage, readHackage', parseHackage
, module Data.Map
, module Data.Version
, module Distribution.Package
, module Distribution.PackageDescription
)
where
import qualified Codec.Archive.Tar as Tar
import Data.ByteString.Lazy.Char8 ( ByteString )
import qualified Data.ByteString.Lazy.Char8 as BS
import Data.Map
import Data.Maybe
import Data.Version
import System.Directory
import System.FilePath
import Distribution.Package
import Distribution.Text
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
type Hackage = Map String (Map Version GenericPackageDescription)
readHackage :: IO Hackage
readHackage = do
homedir <- getHomeDirectory
readHackage' (joinPath [ homedir, ".cabal", "packages", "hackage.haskell.org", "00-index.tar" ])
readHackage' :: FilePath -> IO Hackage
readHackage' = fmap parseHackage . BS.readFile
parseHackage :: ByteString -> Hackage
parseHackage = Tar.foldEntries addEntry empty error . Tar.read
where
addEntry :: Tar.Entry -> Hackage -> Hackage
addEntry e db = case splitDirectories (Tar.entryPath e) of
path@[name,vers,_] -> case Tar.entryContent e of
Tar.NormalFile buf _ -> add name vers buf db
_ -> error ("unexpected content of " ++ show path)
_ -> db
add :: String -> String -> ByteString -> Hackage -> Hackage
add name version pkg = insertWith union name (singleton (pVersion version) (pPackage name pkg))
pPackage :: String -> ByteString -> GenericPackageDescription
pPackage name buf = case parsePackageDescription (BS.unpack buf) of
ParseOk _ a -> a
ParseFailed err -> error ("cannot parse cabal file " ++ show name ++ ": " ++ show err)
pVersion :: String -> Version
pVersion str = fromMaybe (error $ "cannot parse version " ++ show str) (simpleParse str)