packages feed

sensei-0.7.0: src/Run.hs

{-# LANGUAGE LambdaCase #-}
module Run (
  run
, runWeb
) where

import           Imports

import           System.Exit
import           System.FSNotify

import qualified HTTP
import qualified Session
import           Session (Session, Config(..))

import           EventQueue
import           Trigger
import           Util

waitForever :: IO ()
waitForever = forever $ threadDelay 10000000

watchFiles :: EventQueue -> IO ()
watchFiles queue = do
  watch $ \ case
    Added file _ _ -> emit $ FileEvent FileAdded file
    Modified file _ _ -> emit $ FileEvent FileModified file
    ModifiedAttributes _file _ _ -> pass
    Removed file _ _ -> emit $ FileEvent FileRemoved file
    WatchedDirectoryRemoved _file _ _ -> pass
    CloseWrite file _ _ -> emit $ FileEvent FileModified file
    Unknown file _ _ _ -> emit $ FileEvent FileModified file
  where
    emit = emitEvent queue

    watch action = void . forkIO $ do
      withManager $ \ manager -> do
        _stopListening <- watchTree manager "." isInteresting action
        waitForever
      where
        isInteresting = (&&) <$> isFile <*> not . isBoring . eventPath
        isFile = eventIsDirectory >>> (== IsFile)

watchInput :: EventQueue -> IO ()
watchInput queue = void . forkIO $ do
  input <- getContents
  forM_ (lines input) $ \_ -> do
    emitEvent queue TriggerAll
  emitEvent queue Done

run :: FilePath -> [String] -> IO ()
run startupFile args = do
  queue <- newQueue
  watchFiles queue
  watchInput queue
  lastOutput <- newMVar (True, "")
  HTTP.withServer (readMVar lastOutput) $ do
    let
      saveOutput :: IO (Bool, String) -> IO ()
      saveOutput action = modifyMVar_ lastOutput $ \_ -> action

      go = do
        status <- withSession startupFile args $ \ session -> do
          let
            triggerAction = saveOutput (trigger session)
            triggerAllAction = saveOutput (triggerAll session)
          triggerAction
          processQueue queue triggerAllAction triggerAction
        case status of
          Reload -> go
          Terminate -> return ()
    go

runWeb :: FilePath -> [String] -> IO ()
runWeb startupFile args = do
  withSession startupFile args $ \session -> do
    _ <- trigger session
    lock <- newMVar ()
    HTTP.withServer (withMVar lock $ \() -> trigger session) $ do
      waitForever

withSession :: FilePath -> [String] -> (Session -> IO a) -> IO a
withSession startupFile args action = do
  check <- dotGhciWritableByOthers
  when check $ do
    putStrLn ".ghci is writable by others, you can fix this with:"
    putStrLn ""
    putStrLn "    chmod go-w .ghci ."
    putStrLn ""
    exitFailure
  Session.withSession config args action
  where
    config :: Config
    config = Config {
      configIgnoreDotGhci = False
    , configVerbose = True
    , configStartupFile = startupFile
    }