{- | Discover the GHC version via the package database. Requirements:

     * the package database must be compatible, which is usually not the case
       across major ghc versions.

     * the 'ghc' package is registered, which is not always the case.
 -}
module GHC.Check.PackageDb where

import           Control.Monad.Trans.Class as Monad (MonadTrans (lift))
import           Data.Maybe                (fromMaybe)
import           Data.String               (IsString (fromString))
import           Data.Version              (Version)
import           GHC                       (setSessionDynFlags, runGhc, getSessionDynFlags, Ghc)
import           GHC.Exts                  (IsList (fromList), toList)
import           Maybes                    (MaybeT (MaybeT), runMaybeT)
import           Module                    (componentIdToInstalledUnitId)
import           PackageConfig             (PackageName (PackageName))
import           Packages                  (lookupInstalledPackage, lookupPackageName)
import           Packages                  (InstalledPackageInfo (packageVersion))

-- | @getPackageVersion p@ returns the version of package @p@ in
--     the package database
getPackageVersion :: String -> Ghc (Maybe Version)
getPackageVersion packageName = runMaybeT $ do
    dflags <- Monad.lift getSessionDynFlags
    component <- MaybeT $ return $ lookupPackageName dflags $ PackageName $ fromString packageName
    p <- MaybeT $ return $ lookupInstalledPackage dflags (componentIdToInstalledUnitId component)
    return $ packageVersion p

-- | @getPackageVersionIO ghc-libdir p@ returns the version of package @p@
--   in the default package database
getPackageVersionIO :: FilePath -> String -> IO (Maybe Version)
getPackageVersionIO libdir package = runGhc (Just libdir) $ do
    -- initialize the Ghc session
    -- there's probably a beteter way to do this.
    dflags <- getSessionDynFlags
    _ <- setSessionDynFlags dflags

    getPackageVersion package