texbuilder-0.1.0.1: TexBuilder/Utils/Inotify.hs
module TexBuilder.Utils.Inotify where
import TexBuilder.Utils.BinSem
import Control.Concurrent.MVar
import Control.Monad
import Control.Monad.Extra
import System.INotify
import System.Directory
import System.FilePath
-- Be careful with this stuff.
-- Inotify is _inode_ based, but these functions want
-- to watch _paths_. So they reregister the watches
-- when necessary. Still it is probably best to look
-- at the implementation before using them.
-- Also this whole business is rather error prone..
-- ^ Simple version of /withEvent/
onEvent :: [EventVariety] -> FilePath -> IO a -> IO ()
onEvent variety file k = withEvent variety file (const k)
-- ^ Execute action once an event involving the given
-- filepath happens.
-- This function blocks.
withEvent :: [EventVariety]
-> FilePath
-> (Event -> IO a)
-> IO ()
withEvent variety file k =
withINotify $ \inotify -> do
sem <- newBinSem
wd <- addWatch inotify variety file
(k >=> const (trySignal' sem))
wait sem
removeWatch wd
-- ^ Simple version of /loopWithEvent/
loopOnEvent :: [EventVariety] -> FilePath -> IO Bool -> IO ()
loopOnEvent variety file k = loopWithEvent variety file (const k)
-- ^ Execute action every time an Event involving the given
-- filepath happens untils the callback returns True.
-- This function blocks.
loopWithEvent :: [EventVariety] -- ^ Events to watch
-> FilePath -- ^ Filepath to watch
-> (Event -> IO Bool)
-- ^ Callback. If it returns True we stop looping
-> IO ()
loopWithEvent variety file k =
withINotify $ \inotify -> do
doneMVar <- newEmptyMVar
loopWithEventImpl variety file k inotify doneMVar
loopWithEventImpl :: [EventVariety]
-> FilePath
-> (Event -> IO Bool)
-> INotify
-> MVar Bool
-> IO ()
loopWithEventImpl variety file k inotify doneMVar = loop
where
loop = do
wd <- watch
done <- takeMVar doneMVar
removeWatch wd
unless done loop
watch = addWatch inotify variety file
(k >=> putMVar doneMVar)
waitForFile :: FilePath -> IO ()
waitForFile file =
loopOnEvent [Create] dir (doesFileExist file)
where dir = takeDirectory file
onFileEx :: FilePath -> IO a -> IO a
onFileEx file action =
unlessM
(doesFileExist file)
(waitForFile file)
*> action