{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Stackage.CorePackages
    ( getCorePackages
    , getCoreExecutables
    , getGhcVersion
    ) where

import qualified Data.Text        as T
import           Filesystem       (listDirectory)
import           Stackage.Prelude
import           System.Directory (findExecutable)

-- | Get a @Map@ of all of the core packages. Core packages are defined as
-- packages which ship with GHC itself.
--
-- Precondition: GHC global package database has only core packages, and GHC
-- ships with just a single version of each packages.
getCorePackages :: IO (Map PackageName Version)
getCorePackages =
    withCheckedProcess cp $ \ClosedStream src Inherited ->
        src $$ decodeUtf8C =$ linesUnboundedC =$ foldMapMC parsePackage
  where
    cp = proc "ghc-pkg" ["--no-user-package-conf", "list"]
    parsePackage t
        | ":" `isInfixOf` t = return mempty
        | Just p <- stripSuffix "-" p' = singletonMap
            <$> simpleParse p
            <*> simpleParse v
        | otherwise = return mempty
      where
        (p', v) = T.breakOnEnd "-" $ dropParens $ T.strip t

        dropParens s
            | length s > 2 && headEx s == '(' && lastEx s == ')' =
                initEx $ tailEx s
            | otherwise = s

-- | A list of executables that are shipped with GHC.
getCoreExecutables :: IO (Set ExeName)
getCoreExecutables = do
    mfp <- findExecutable "ghc"
    dir <-
        case mfp of
            Nothing -> error "No ghc executable found on PATH"
            Just fp -> return $ directory $ fpFromString fp
    (setFromList . map (ExeName . fpToText . filename)) <$> listDirectory dir

getGhcVersion :: IO Version
getGhcVersion = do
    withCheckedProcess (proc "ghc" ["--numeric-version"]) $
        \ClosedStream src Inherited ->
            (src $$ decodeUtf8C =$ foldC) >>= simpleParse