module System.TestLoop.Internal.Watcher (reloadTestSuite) where
import Control.Monad (liftM, sequence)
import Control.Monad.Trans (MonadIO (..))
import Data.List (intercalate, isPrefixOf,
isSuffixOf, nub)
import Data.Monoid (mconcat, First(..))
import qualified Filesystem.Path as FS
import qualified Filesystem.Path.CurrentOS as FS
import Language.Haskell.Interpreter (InterpreterError (..), as,
errMsg, interpret,
loadModules, setImportsQ,
setTopLevelModules)
import Language.Haskell.Interpreter.Unsafe (unsafeRunInterpreterWithArgs)
import Data.Time.LocalTime (getZonedTime)
import System.Directory (doesDirectoryExist,
getCurrentDirectory,
getDirectoryContents)
import System.FilePath (joinPath)
import System.TestLoop.Internal.Signal
import System.TestLoop.Internal.Types
import System.TestLoop.Util
_getPackageDatabaseFile :: FilePath
-> (FilePath -> Bool)
-> IO (Maybe FilePath)
_getPackageDatabaseFile folderName isPackageDatabase = do
cabalDevExists <- doesDirectoryExist folderName
if (not cabalDevExists)
then return Nothing
else do
dir <- getCurrentDirectory
let cabalDevDir = joinPath [dir, folderName]
packages <- getDirectoryContents cabalDevDir
case filter isPackageDatabase packages of
(packagesFile:_) -> return $ Just (joinPath [cabalDevDir, packagesFile])
getCabalDevPackageDatabaseFile :: IO (Maybe FilePath)
getCabalDevPackageDatabaseFile =
_getPackageDatabaseFile "cabal-dev" ("packages-" `isPrefixOf`)
getCabalSandboxPackageDatabaseFile :: IO (Maybe FilePath)
getCabalSandboxPackageDatabaseFile =
_getPackageDatabaseFile ".cabal-sandbox" ("packages.conf.d" `isSuffixOf`)
getPackageDatabaseFile :: IO (Maybe FilePath)
getPackageDatabaseFile =
liftM (getFirst . mconcat . map First) $
sequence [ getCabalSandboxPackageDatabaseFile
, getCabalDevPackageDatabaseFile ]
reloadTestSuite :: MainModuleName
-> MainModulePath
-> HsSourcePaths
-> FS.FilePath
-> IO ()
reloadTestSuite moduleName modulePath sourcePaths modifiedFile
| isNotEmacsFile = do
reloadTestSuite_
| otherwise = return ()
where
isNotEmacsFile = not ('#' `elem` (FS.encodeString $ FS.filename modifiedFile))
reloadTestSuite_ = do
printTimeHeader
result <- protectHandlers runInterpreter
case result of
Left err -> putStrLn "" >> putStrLn (format err)
Right _ -> return ()
printTimeHeader = do
time <- getZonedTime
putStrLn ""
putStrLn $ replicate 80 '-'
putStr "-- "
putStr (show time)
putStr " "
let remaindingWidth = 76 (length (show time))
putStrLn $ replicate remaindingWidth '-'
format :: InterpreterError -> String
format (UnknownError e) = "Unknown interpreter error:\r\n\r\n" ++ e
format (NotAllowed e) = "Interpreter action not allowed:\r\n\r\n" ++ e
format (GhcException e) = "GHC error:\r\n\r\n" ++ e
format (WontCompile errs) = concat ["Compile errors:\r\n\r\n",
intercalate "\r\n" $ nub $ map errMsg errs]
runInterpreter = do
mPackageDatabaseFile <- getPackageDatabaseFile
let args = case mPackageDatabaseFile of
Just file -> [ "-i " ++ join ":" sourcePaths
, "-package-conf " ++ file]
Nothing -> [ "-i " ++ join ":" sourcePaths]
unsafeRunInterpreterWithArgs args interpreterAction
interpreterAction = do
loadModules [modulePath]
setTopLevelModules [moduleName]
setImportsQ [("Prelude", Nothing)]
execution <- interpret "main" (as :: IO ())
liftIO $ execution