diff --git a/.gitignore b/.gitignore index 40c4550..147f23c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ .hg/ _darcs/ +.cabal-sandbox/ +cabal.sandbox.config +test/.test.json.swp *~ dist/ *.prof diff --git a/linux-inotify.cabal b/linux-inotify.cabal index 7ee7d2b..8a96b21 100644 --- a/linux-inotify.cabal +++ b/linux-inotify.cabal @@ -53,6 +53,19 @@ library ghc-options: -Wall +test-suite test + hs-source-dirs: + src, + test + type: + exitcode-stdio-1.0 + main-is: + test.hs + build-depends: + base >= 4.7 && < 5, + unix, + linux-inotify + source-repository head type: git location: http://github.com/lpsmith/linux-inotify diff --git a/src/System/Linux/Inotify.hsc b/src/System/Linux/Inotify.hsc index 7f98cd9..57a0d42 100644 --- a/src/System/Linux/Inotify.hsc +++ b/src/System/Linux/Inotify.hsc @@ -79,8 +79,9 @@ import Prelude hiding (init) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8 -import Control.Applicative -import Data.Monoid +-- import Control.Applicative +-- import Data.Monoid +-- https://ghc.haskell.org/trac/ghc/wiki/Migration/7.10#GHCsaysTheimportof...isredundant import Data.Typeable import Data.Function ( on ) import Data.Word @@ -325,7 +326,7 @@ data Event = Event -- to the watched directory. -- -- The proper Haskell interpretation of this seems to be to use - -- 'GHC.IO.Encoding.getFileSystemEncoding' and then unpack it to a + -- 'GHC.IO.Encoding.getFileSystemEncoding' and then unpack it to a -- 'String' or decode it using the text package. } deriving (Eq, Show, Typeable) diff --git a/test/test.hs b/test/test.hs new file mode 100644 index 0000000..5ae0a3a --- /dev/null +++ b/test/test.hs @@ -0,0 +1,64 @@ +module Main where + +import System.Environment +import System.Exit +import Prelude hiding (reverse, log) +import qualified System.Linux.Inotify as IN +import Data.Monoid(mconcat) +import Control.Monad(forever) +import Control.Exception(bracket) +import GHC.Conc.Sync(ThreadId) +import Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef) +import System.Posix.Signals(installHandler, Handler(Catch), sigINT, sigTERM, raiseSignal) +import Control.Concurrent(forkIO, threadDelay) +import Control.Concurrent.MVar(newEmptyMVar, takeMVar, putMVar, MVar) + +log :: String -> IO() +log x = putStrLn $ "[linux-inotify]: " ++ x + +events :: IN.Mask a +events = mconcat [IN.in_MODIFY] + +initFileReload :: IORef Int -> String -> IO ThreadId +initFileReload counter dir = do + forkIO.bracket IN.init IN.close $ \ind -> do + _ <- IN.addWatch ind dir events + forever $ do + e <- IN.getEvent ind + log $ show e + atomicModifyIORef' counter (\n -> (n + 1, ())) + +testFileWrite :: String -> IO () +testFileWrite path = do + writeFile path "test" + log "Test writing to file" + threadDelay $ 1 + raiseSignal sigINT + -- sigTERM will not be caught :/ + +handler :: MVar () -> IO () +handler s_interrupted = + putMVar s_interrupted () + +recvFunction :: IORef Int -> MVar () -> IO () +recvFunction counter signal = do + output <- takeMVar signal + n <- readIORef counter + log $ "Interrupt Received. Stopping watcher" ++ show n + if n == 1 + then exitSuccess + else exitFailure + +main:: IO() +main = do + -- [file] <- getArgs + -- https://github.com/haskell/cabal/issues/4643 + let file = "test/test.json" + counter <- newIORef 0 + log $ "watching file: " ++ file + _ <- initFileReload counter file + testFileWrite file + s_interrupted <- newEmptyMVar + installHandler sigTERM (Catch $ handler s_interrupted) Nothing + installHandler sigINT (Catch $ handler s_interrupted) Nothing + recvFunction counter s_interrupted diff --git a/test/test.json b/test/test.json new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/test/test.json @@ -0,0 +1 @@ +test \ No newline at end of file