module HsDev.Tools.Ghc.Worker (
SessionType(..), SessionConfig(..),
GhcM, GhcWorker, MGhcT(..), runGhcM,
ghcWorker,
workerSession, ghcSession, ghciSession, haddockSession, tmpSession,
Ghc,
LogT(..),
module HsDev.Tools.Ghc.Base,
module HsDev.Tools.Ghc.Repl,
module HsDev.Tools.Ghc.MGhc,
module Control.Concurrent.Worker
) where
import Control.Lens (view)
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.Catch
import Data.Monoid
import qualified System.Log.Simple as Log
import System.Log.Simple.Monad (MonadLog(..), LogT(..), withLog)
import Text.Format hiding (withFlags)
import Exception (ExceptionMonad(..), ghandle)
import GHC hiding (Warning, Module)
import GHC.Paths
import Control.Concurrent.Worker
import HsDev.PackageDb.Types
import HsDev.Tools.Ghc.Base
import HsDev.Tools.Ghc.Repl
import HsDev.Tools.Ghc.MGhc
data SessionType = SessionGhci | SessionGhc | SessionHaddock | SessionTmp deriving (Eq, Ord)
data SessionConfig = SessionConfig SessionType PackageDbStack deriving (Eq, Ord)
instance Show SessionType where
show SessionGhci = "ghci"
show SessionGhc = "ghc"
show SessionHaddock = "haddock"
show SessionTmp = "tmp"
instance Formattable SessionType
instance Show SessionConfig where
show (SessionConfig t pdb) = "{} {}" ~~ t ~~ pdb
instance Formattable SessionConfig
type GhcM a = MGhcT SessionConfig (First DynFlags) (LogT IO) a
type GhcWorker = Worker (MGhcT SessionConfig (First DynFlags) (LogT IO))
instance (Monad m, GhcMonad m) => GhcMonad (ReaderT r m) where
getSession = lift getSession
setSession = lift . setSession
instance ExceptionMonad m => ExceptionMonad (LogT m) where
gcatch act onError = LogT $ gcatch (runLogT act) (runLogT . onError)
gmask f = LogT $ gmask f' where
f' g' = runLogT $ f (LogT . g' . runLogT)
instance MonadThrow Ghc where
throwM = liftIO . throwM
runGhcM :: MonadLog m => Maybe FilePath -> GhcM a -> m a
runGhcM dir act = do
l <- Log.askLog
liftIO $ withLog l $ runMGhcT dir act
ghcWorker :: MonadLog m => m GhcWorker
ghcWorker = do
l <- Log.askLog
liftIO $ startWorker (withLog l . runGhcM (Just libdir)) (Log.scope "ghc") (ghandle logErr)
where
logErr :: MonadLog m => SomeException -> m ()
logErr e = Log.sendLog Log.Warning ("exception in ghc worker task: {}" ~~ displayException e)
workerSession :: SessionType -> PackageDbStack -> [String] -> GhcM ()
workerSession ty pdbs opts = do
ms <- findSessionBy toKill
forM_ ms $ \s' -> do
Log.sendLog Log.Trace $ "killing session: {}" ~~ view sessionKey s'
deleteSession $ view sessionKey s'
Log.sendLog Log.Trace $ "session: {}" ~~ SessionConfig ty pdbs
switchSession_ (SessionConfig ty pdbs) $ Just initialize
setSessionFlags
where
toKill (SessionConfig ty' pdbs') = or [
(ty == ty' && pdbs /= pdbs'),
(ty /= ty' && ty' `elem` [SessionTmp, SessionHaddock] && ty /= SessionTmp)]
initialize = do
run
dflags <- getSessionDynFlags
setSessionData (First $ Just dflags)
run = case ty of
SessionGhci -> ghcRun pdbsOpts (importModules preludeModules)
SessionGhc -> ghcRun pdbsOpts (return ())
SessionTmp -> ghcRun pdbsOpts (return ())
SessionHaddock -> ghcRunWith noLinkFlags ("-haddock" : pdbsOpts) (return ())
setSessionFlags = do
Log.sendLog Log.Trace $ "setting flags: {}" ~~ unwords opts
mdflags <- fmap (join . fmap getFirst) getSessionData
dflags <- maybe getSessionDynFlags return mdflags
(df', _, _) <- parseDynamicFlags dflags (map noLoc opts)
void $ setSessionDynFlags df'
pdbsOpts = packageDbStackOpts pdbs
ghcSession :: PackageDbStack -> [String] -> GhcM ()
ghcSession = workerSession SessionGhc
ghciSession :: GhcM ()
ghciSession = workerSession SessionGhci userDb []
haddockSession :: PackageDbStack -> [String] -> GhcM ()
haddockSession = workerSession SessionHaddock
tmpSession :: PackageDbStack -> [String] -> GhcM ()
tmpSession = workerSession SessionTmp