{-# LANGUAGE OverloadedStrings #-}
module GhcDatabase
( GhcMetadata(..)
, GhcDatabase
, defaultGhcDatabaseURL
, dbFromList
, dbToList
, ghcVersions
, isEmpty
, metadataForGhc
, baseVersionForGhc
, cabalLibRangeForGhc
, hasGhcVersion
, newest
, parseGhcDatabase
, filterGhcVersions
, excludeGhcVersions
, filterBaseVersionIn
, filterMinCabalVersionIn
) where
import Distribution.Version
import Distribution.Parsec.Class
import Data.Csv
import Data.Foldable (toList)
import qualified Data.ByteString.Lazy as B
import qualified Data.Map.Strict as M
import qualified Data.Set as S
defaultGhcDatabaseURL :: String
defaultGhcDatabaseURL = "https://raw.githubusercontent.com/vabal/vabal-ghc-metadata/master/vabal-ghc-metadata.csv"
data GhcMetadata = GhcMetadata
{ baseVersion :: Version
, minCabalVersion :: Version
}
newtype MetadataEntry = MetadataEntry { unwrapMetadataEntry :: (Version, GhcMetadata) }
instance FromNamedRecord MetadataEntry where
parseNamedRecord r = do
field1 <- r .: "ghcVersion"
ghcVer <- maybe (fail "Expected version") return $ simpleParsec field1
field2 <- r .: "baseVersion"
baseVer <- maybe (fail "Expected version") return $ simpleParsec field2
field3 <- r .: "minCabalVersion"
minCabalVer <- maybe (fail "Expected version") return $ simpleParsec field3
return $ MetadataEntry (ghcVer, GhcMetadata baseVer minCabalVer)
newtype GhcDatabase = GhcDatabase { unwrapDb :: M.Map Version GhcMetadata }
dbFromList :: [(Version, GhcMetadata)] -> GhcDatabase
dbFromList = GhcDatabase . M.fromList
dbToList :: GhcDatabase -> [(Version, GhcMetadata)]
dbToList = M.toList . unwrapDb
ghcVersions :: GhcDatabase -> S.Set Version
ghcVersions = M.keysSet . unwrapDb
isEmpty :: GhcDatabase -> Bool
isEmpty = M.null . unwrapDb
newest :: GhcDatabase -> Maybe (Version, GhcMetadata)
newest = M.lookupMax . unwrapDb
metadataForGhc :: GhcDatabase -> Version -> Maybe GhcMetadata
metadataForGhc (GhcDatabase db) v = M.lookup v db
baseVersionForGhc :: GhcDatabase -> Version -> Maybe Version
baseVersionForGhc db v = baseVersion <$> metadataForGhc db v
cabalLibRangeForGhc :: GhcDatabase -> Version -> Maybe VersionRange
cabalLibRangeForGhc db v = orLaterVersion . minCabalVersion <$> metadataForGhc db v
parseGhcDatabase :: B.ByteString -> Either String GhcDatabase
parseGhcDatabase contents = do
(_, entries) <- decodeByName contents
return . GhcDatabase . M.fromList . map unwrapMetadataEntry $ toList entries
filterGhcVersions :: GhcDatabase -> S.Set Version -> GhcDatabase
filterGhcVersions (GhcDatabase db) = GhcDatabase . M.restrictKeys db
excludeGhcVersions :: GhcDatabase -> S.Set Version -> GhcDatabase
excludeGhcVersions (GhcDatabase db) = GhcDatabase . M.withoutKeys db
hasGhcVersion :: GhcDatabase -> Version -> Bool
hasGhcVersion (GhcDatabase s) v = v `M.member` s
isVersionInRange :: VersionRange -> Version -> Bool
isVersionInRange = flip withinRange
filterBaseVersionIn :: GhcDatabase -> VersionRange -> GhcDatabase
filterBaseVersionIn (GhcDatabase db) vr =
GhcDatabase $ M.filter (isVersionInRange vr . baseVersion) db
filterMinCabalVersionIn :: GhcDatabase -> VersionRange -> GhcDatabase
filterMinCabalVersionIn (GhcDatabase db) vr =
GhcDatabase $ M.filter (not . isNoVersion . intersectVersionRanges vr . orLaterVersion . minCabalVersion) db