hinotify 0.3.1 → 0.3.2
raw patch · 17 files changed
+870/−30 lines, 17 filesdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base
API changes (from Hackage documentation)
- System.INotify: isDirecotry :: Event -> Bool
+ System.INotify: instance Eq INotify
- System.INotify: removeWatch :: INotify -> WatchDescriptor -> IO ()
+ System.INotify: removeWatch :: WatchDescriptor -> IO ()
Files
- ANNOUNCE +58/−0
- Makefile +7/−0
- README +31/−16
- README.html +247/−0
- docs/hcar/hinotify-Lh.tex +36/−0
- examples/DirTree/DirTree.hs +111/−0
- examples/simple/simple.hs +17/−0
- hinotify.cabal +4/−4
- hinotify.css +89/−0
- src/System/INotify.hsc +12/−10
- tests/Utils.hs +55/−0
- tests/test-all +31/−0
- tests/test001-list-dir-contents.hs +20/−0
- tests/test002-writefile.hs +24/−0
- tests/test003-removefile.hs +35/−0
- tests/test004-modify-file.hs +47/−0
- tests/test005-move-file.hs +46/−0
+ ANNOUNCE view
@@ -0,0 +1,58 @@+Greetings!++I'm pleased to announce hinotify 0.1, a library to inotify[1] which has+been part of the Linux kernel since 2.6.13.++inotify provides file system event notification, simply add a watcher to+a file or directory and get an event when it is accessed or modified.++The API basically consists of:++inotify_init :: IO INotify+inotify_add_watch :: INotify+ -> [EventVariety] -- different events to listen on+ -> FilePath -- file/directory to watch+ -> (Event -> IO ()) -- event handler+ -> IO WatchDescriptor+inotify_rm_watch :: INotify -> WatchDescriptor -> IO ()++A sample program:++> import System.Directory+> import System.IO+>+> import System.INotify+>+> main :: IO ()+> main = do+> inotify <- inotify_init+> print inotify+> home <- getHomeDirectory+> wd <- inotify_add_watch inotify+> [Open,Close,Access,Modify,Move]+> home+> print+> print wd+> putStrLn "Listens to your home directory. Hit enter to terminate."+> getLine+> inotify_rm_watch inotify wd++The code is available via www:++http://haskell.org/~kolmodin/code/hinotify/download/hinotify-0.1.tar.gz++and via darcs:++ darcs get http://haskell.org/~kolmodin/code/hinotify/++The API is available at:++ http://haskell.org/~kolmodin/code/hinotify/docs/api/++The library is very young and I'm most grateful for feedback on the API,+and what else you might have to suggest.++Cheers,+ Lennart Kolmodin++[1] http://www.kernel.org/pub/linux/kernel/people/rml/inotify/
+ Makefile view
@@ -0,0 +1,7 @@++.PHONY : docs++docs : README.html++%.html : %+ pandoc -s -S --toc -c hinotify.css $< -o $@
README view
@@ -1,6 +1,6 @@ % hinotify: inotify for Haskell-% Lennart Kolmodin <kolmodin@gentoo.org>-% December 26, 2007-2009+% Lennart Kolmodin <kolmodin@gmail.com>+% December 26, 2007-2011 About -----@@ -21,21 +21,36 @@ News ---- +**hinotify 0.3.2**++* Make each `WatchDescriptor` contain its `INotify`. Changes to the function types:++> -removeWatch :: INotify -> WatchDescriptor -> IO ()+> +removeWatch :: WatchDescriptor -> IO ()++* Fix typo in declaration of `Deleted` in `data Event`;++> - { isDirecotry :: Bool+> + { isDirectory :: Bool+ **hinotify 0.3.1**-: * Use `inotify.h` from `glibc` rather than from the linux headers, as++* Use `inotify.h` from `glibc` rather than from the linux headers, as recommended upstream. **hinotify 0.3**-: * Compiles with GHC 6.12, GHC 6.10.4, GHC 6.8.2 and GHC 6.6.1 +* Compiles with GHC 6.12, GHC 6.10.4, GHC 6.8.2 and GHC 6.6.1+ **hinotify 0.2**-: * Updates to the API- - Function names is now in semiCamelCase- - Restructure event parameters to make it more consistent- * Small test suit in `tests/`- * Compiles with GHC 6.8.2 and GHC 6.6.1- * Requires Cabal 1.2 +* Updates to the API+ - Function names is now in semiCamelCase+ - Restructure event parameters to make it more consistent+* Small test suit in `tests/`+* Compiles with GHC 6.8.2 and GHC 6.6.1+* Requires Cabal 1.2+ **hinotify 0.1** : Initial release @@ -50,7 +65,7 @@ -> FilePath -- file/directory to watch -> (Event -> IO ()) -- event handler -> IO WatchDescriptor- removeWatch :: INotify -> WatchDescriptor -> IO ()+ removeWatch :: WatchDescriptor -> IO () A sample program: @@ -72,7 +87,7 @@ print wd putStrLn "Listens to your home directory. Hit enter to terminate." getLine- removeWatch inotify wd+ removeWatch wd Download@@ -80,7 +95,7 @@ The code is available via the [homepage], and via darcs: - darcs get --partial http://haskell.org/~kolmodin/code/hinotify/+ darcs get --partial http://code.haskell.org/hinotify/ The [API] is available online. @@ -92,7 +107,7 @@ Lennart Kolmodin -`kolmodin at gentoo.org`+`kolmodin at gmail.com` Legal -----@@ -100,8 +115,8 @@ This software is released under a BSD-style license. See LICENSE for more details. -Copyright © 2007 Lennart Kolmodin+Copyright © 2007-2011 Lennart Kolmodin -[homepage]: http://haskell.org/~kolmodin/code/hinotify/+[homepage]: http://code.haskell.org/hinotify/ [API]: http://hackage.haskell.org/packages/archive/hinotify/latest/doc/html/System-INotify.html
+ README.html view
@@ -0,0 +1,247 @@+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">+<html xmlns="http://www.w3.org/1999/xhtml">+<head>+ <title>hinotify: inotify for Haskell</title>+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />+ <meta name="generator" content="pandoc" />+ <meta name="author" content="Lennart Kolmodin + '+''+e+''+'');+ // -->+ kolmodin at gmail dot com" />+ <meta name="date" content="December 26, 2007–2011" />+ <link rel="stylesheet" href="hinotify.css" type="text/css" />+</head>+<body>+<h1 class="title">hinotify: inotify for Haskell</h1>+<div id="TOC"+><ul+ ><li+ ><a href="#about"+ >About</a+ ></li+ ><li+ ><a href="#news"+ >News</a+ ></li+ ><li+ ><a href="#api"+ >API</a+ ></li+ ><li+ ><a href="#download"+ >Download</a+ ></li+ ><li+ ><a href="#author"+ >Author</a+ ></li+ ><li+ ><a href="#legal"+ >Legal</a+ ></li+ ></ul+ ></div+>+<div id="about"+><h2+ ><a href="#TOC"+ >About</a+ ></h2+ ><p+ >hinotify, a library to <a href="http://www.kernel.org/pub/linux/kernel/people/rml/inotify/"+ >inotify</a+ > which has been part of the Linux kernel since 2.6.13.</p+ ><p+ >inotify provides file system event notification, simply add a watcher to a file or directory and get an event when it is accessed or modified.</p+ ><p+ >This module is named <code+ >hinotify</code+ >.</p+ ><p+ >See example code in the <code+ >examples</code+ > directory, distributed with the source code.</p+ ></div+><div id="news"+><h2+ ><a href="#TOC"+ >News</a+ ></h2+ ><p+ ><strong+ >hinotify 0.3.2</strong+ ></p+ ><ul+ ><li+ >Make each <code+ >WatchDescriptor</code+ > contain its <code+ >INotify</code+ >. Changes to the function types:</li+ ></ul+ ><blockquote+ ><pre+ ><code+ > -removeWatch :: INotify -> WatchDescriptor -> IO ()+ +removeWatch :: WatchDescriptor -> IO ()+</code+ ></pre+ ></blockquote+ ><ul+ ><li+ >Fix typo in declaration of <code+ >Deleted</code+ > in <code+ >data Event</code+ >;</li+ ></ul+ ><blockquote+ ><pre+ ><code+ > - { isDirecotry :: Bool+ + { isDirectory :: Bool+</code+ ></pre+ ></blockquote+ ><p+ ><strong+ >hinotify 0.3.1</strong+ ></p+ ><ul+ ><li+ >Use <code+ >inotify.h</code+ > from <code+ >glibc</code+ > rather than from the linux headers, as recommended upstream.</li+ ></ul+ ><p+ ><strong+ >hinotify 0.3</strong+ ></p+ ><ul+ ><li+ >Compiles with GHC 6.12, GHC 6.10.4, GHC 6.8.2 and GHC 6.6.1</li+ ></ul+ ><p+ ><strong+ >hinotify 0.2</strong+ ></p+ ><ul+ ><li+ >Updates to the API<ul+ ><li+ >Function names is now in semiCamelCase</li+ ><li+ >Restructure event parameters to make it more consistent</li+ ></ul+ ></li+ ><li+ >Small test suit in <code+ >tests/</code+ ></li+ ><li+ >Compiles with GHC 6.8.2 and GHC 6.6.1</li+ ><li+ >Requires Cabal 1.2</li+ ></ul+ ><dl+ ><dt+ ><strong+ >hinotify 0.1</strong+ ></dt+ ><dd+ >Initial release</dd+ ></dl+ ></div+><div id="api"+><h2+ ><a href="#TOC"+ >API</a+ ></h2+ ><p+ >The API basically consists of:</p+ ><pre+ ><code+ >initINotify :: IO INotify+addWatch :: INotify+ -> [EventVariety] -- different events to listen on+ -> FilePath -- file/directory to watch+ -> (Event -> IO ()) -- event handler+ -> IO WatchDescriptor+removeWatch :: WatchDescriptor -> IO ()+</code+ ></pre+ ><p+ >A sample program:</p+ ><pre+ ><code+ >import System.Directory+import System.IO++import System.INotify++main :: IO ()+main = do+ inotify <- initINotify+ print inotify+ home <- getHomeDirectory+ wd <- addWatch+ inotify+ [Open,Close,Access,Modify,Move]+ home+ print+ print wd+ putStrLn "Listens to your home directory. Hit enter to terminate."+ getLine+ removeWatch wd+</code+ ></pre+ ></div+><div id="download"+><h2+ ><a href="#TOC"+ >Download</a+ ></h2+ ><p+ >The code is available via the <a href="http://code.haskell.org/hinotify/"+ >homepage</a+ >, and via darcs:</p+ ><pre+ ><code+ >darcs get --partial http://code.haskell.org/hinotify/+</code+ ></pre+ ><p+ >The <a href="http://hackage.haskell.org/packages/archive/hinotify/latest/doc/html/System-INotify.html"+ >API</a+ > is available online.</p+ ><p+ >I’m most grateful for feedback on the API, and what else you might have to suggest.</p+ ></div+><div id="author"+><h2+ ><a href="#TOC"+ >Author</a+ ></h2+ ><p+ >Lennart Kolmodin</p+ ><p+ ><code+ >kolmodin at gmail.com</code+ ></p+ ></div+><div id="legal"+><h2+ ><a href="#TOC"+ >Legal</a+ ></h2+ ><p+ >This software is released under a BSD-style license. See LICENSE for more details.</p+ ><p+ >Copyright © 2007–2011 Lennart Kolmodin</p+ ></div+>+</body>+</html>+
+ docs/hcar/hinotify-Lh.tex view
@@ -0,0 +1,36 @@+\begin{hcarentry}{hinotify}+\report{Lennart Kolmodin}+\status{alive}+\makeheader++``hinotify'' is a simple Haskell wrapper for the Linux kernel's inotify+mechanism. inotify allows applications to watch file changes since+Linux kernel 2.6.13. You can for example use it to do a proper+locking procedure on a set of files, or keep your application up do+date on a directory of files in a fast and clean way.++As file and directory notification is available for many operating systems+upcoming work will include to try to find a common API that could be shared+for all platforms. Last work has been to see what's possible to do under+Microsoft Windows, and finding a suiting API for both platforms. This has+been a joint work with Niklas Broberg. We're still looking for contributors+to *BSD and Mac OS X. If you're interested, contact us.++\FurtherReading+\begin{compactitem}+\item Development version:++ \texttt{darcs get}++ \url{http://www.haskell.org/~kolmodin/code/hinotify/}+\item Latest released version:++ \url{http://www.haskell.org/~kolmodin/code/hinotify/download/}+\item Documentation:++ \url{http://www.haskell.org/~kolmodin/code/hinotify/docs/api}+\item inotify:++ \url{http://www.kernel.org/pub/linux/kernel/people/rml/inotify/}+\end{compactitem}+\end{hcarentry}
+ examples/DirTree/DirTree.hs view
@@ -0,0 +1,111 @@+-- Duncan Coutts 2006-2007+-- Requires gtk2hs 0.9.11++import qualified Data.Map as Map+import System.Directory+import System.Environment+import Control.Concurrent++import Data.IORef+import Control.Monad (liftM)+import Ix (inRange)++import System.INotify++import Graphics.UI.Gtk hiding (TreeModelFlags(TreeModelListOnly), cellText)+import Graphics.UI.Gtk.ModelView.CellLayout+import Graphics.UI.Gtk.ModelView.Types (TypedTreeModelClass)+import Graphics.UI.Gtk.ModelView.TreeModel (TreeModelFlags(TreeModelListOnly))+import Graphics.UI.Gtk.ModelView.CellRendererText (cellText)+import Graphics.UI.Gtk.ModelView.CustomStore+import Graphics.UI.Gtk.TreeList.TreeIter++instance TypedTreeModelClass (CustomTreeModel a)++dirModelNew :: FilePath -> IO (CustomTreeModel () FilePath)+dirModelNew path = do+ + dirContents <- getDirectoryContents path+ + rows <- newIORef (Map.fromList (zip dirContents (repeat ())))++ model <- customTreeModelNew () CustomTreeModelImplementation {+ customTreeModelGetFlags = return [TreeModelListOnly],+ customTreeModelGetIter = \[n] -> return (Just (TreeIter 0 (fromIntegral n) 0 0)),+ customTreeModelGetPath = \(TreeIter _ n _ _) -> return [fromIntegral n],+ customTreeModelGetRow = \(TreeIter _ n _ _) ->+ readIORef rows >>= \rows -> + if inRange (0, Map.size rows - 1) (fromIntegral n)+ then return (fst $ Map.elemAt (fromIntegral n) rows)+ else fail "DirModel.getRow: iter does not refer to a valid entry",++ customTreeModelIterNext = \(TreeIter _ n _ _) ->+ readIORef rows >>= \rows ->+ if n >= fromIntegral (Map.size rows) - 1+ then return Nothing+ else return (Just (TreeIter 0 (n+1) 0 0)),+ customTreeModelIterChildren = \_ -> return Nothing,+ customTreeModelIterHasChild = \_ -> return False,+ customTreeModelIterNChildren = \index -> readIORef rows >>= \rows ->+ case index of+ Nothing -> return $! Map.size rows+ _ -> return 0,+ customTreeModelIterNthChild = \index n -> case index of+ Nothing -> return (Just (TreeIter 0 (fromIntegral n) 0 0))+ _ -> return Nothing,+ customTreeModelIterParent = \_ -> return Nothing,+ customTreeModelRefNode = \_ -> return (),+ customTreeModelUnrefNode = \_ -> return ()+ }++ notify <- initINotify+ watch <- addWatch notify [Move, Create, Delete] path $ \event -> + let add file = do + index <- atomicModifyIORef rows (\map ->+ let map' = Map.insert file () map+ in (map', Map.findIndex file map'))+ treeModelRowInserted model [index] (TreeIter 0 (fromIntegral index) 0 0)+ remove file = do+ index <- atomicModifyIORef rows (\map ->+ let map' = Map.delete file map+ in (map', Map.findIndex file map))+ treeModelRowDeleted model [index]++ in case event of+ MovedIn _ file _ -> add file+ MovedOut _ file _ -> remove file+ Created _ file -> add file+ Deleted _ file -> remove file+ _ -> putStrLn $ "other event: " ++ show event++ -- TODO: on destroy model (INotify.removeWatch watch)+ + return model++main = do+ initGUI++ win <- windowNew+ win `onDestroy` mainQuit++ args <- getArgs+ let dir = case args of+ [d] -> d+ _ -> "."++ model <- dirModelNew dir++ tv <- treeViewNewWithModel model+ win `containerAdd` tv++ tvc <- treeViewColumnNew+ treeViewAppendColumn tv tvc++ text <- cellRendererTextNew+ cellLayoutPackStart tvc text True+ cellLayoutSetAttributes tvc text model+ (\file -> [cellText := file])++ widgetShowAll win+ timeoutAddFull (yield >> return True) priorityDefaultIdle 50+ mainGUI
+ examples/simple/simple.hs view
@@ -0,0 +1,17 @@+module Main where++import System.Directory+import System.IO++import System.INotify++main :: IO ()+main = do+ inotify <- initINotify+ print inotify+ home <- getHomeDirectory+ wd <- addWatch inotify [Open,Close,Access,Modify,Move] home print+ print wd+ putStrLn "Listens to your home directory. Hit enter to terminate."+ getLine+ removeWatch inotify wd
hinotify.cabal view
@@ -1,5 +1,5 @@ name: hinotify-version: 0.3.1+version: 0.3.2 build-type: Simple synopsis: Haskell binding to INotify description:@@ -9,11 +9,11 @@ accessed or modified. . category: System-homepage: http://haskell.org/~kolmodin/code/hinotify/README.html+homepage: http://code.haskell.org/hinotify/README.html license: BSD3 license-file: LICENSE author: Lennart Kolmodin-maintainer: Lennart Kolmodin <kolmodin@gentoo.org>+maintainer: Lennart Kolmodin <kolmodin@gmail.com> extra-source-files: README cabal-version: >= 1.2 @@ -33,6 +33,6 @@ other-modules: System.INotify.Masks - ghc-options: -fvia-C -Wall+ ghc-options: -Wall hs-source-dirs: src
+ hinotify.css view
@@ -0,0 +1,89 @@+body {+ margin: auto;+ padding-right: 1em;+ padding-left: 1em;+ max-width: 50em; + border-left: 1px solid black;+ border-right: 1px solid black;+ color: black;+ font-family: Verdana, sans-serif;+ font-size: 100%;+ line-height: 140%;+ color: #333; +}+pre {+ border: 1px dotted gray;+ background-color: #9999ff;+ color: #111111;+ padding: 0.5em;+}+code {+ font-family: monospace;+ font-size: 110%;+}+h1 a, h2 a, h3 a, h4 a, h5 a { + text-decoration: none;+ color: #000099; +}+h1, h2, h3, h4, h5 { font-family: verdana;+ font-weight: bold;+ border-bottom: 1px dotted black;+ color: #000099; }+h1 {+ font-size: 130%;+}++h2 {+ font-size: 110%;+ border-bottom: 1px dotted black;+}++h3 {+ font-size: 95%;+}++h4 {+ font-size: 90%;+ font-style: italic;+}++h5 {+ font-size: 90%;+ font-style: italic;+}++h1.title {+ font-size: 150%;+ font-weight: bold;+ text-align: left;+ border: none;+}++dt code {+ font-weight: bold;+}+dd p {+ margin-top: 0;+}++a:link {+ color: #000099+ }++a:visited {+ color: #666699+ }+a:hover {+ color: #666699+ }+a:active {+ color: #000099+ }++#footer {+ padding-top: 1em;+ font-size: 70%;+ color: gray;+ text-align: center;+}+
src/System/INotify.hsc view
@@ -67,8 +67,11 @@ type WDEvent = (WD, Event) data INotify = INotify Handle FD (MVar EventMap) ThreadId ThreadId-data WatchDescriptor = WatchDescriptor Handle WD deriving Eq+data WatchDescriptor = WatchDescriptor INotify WD deriving Eq +instance Eq INotify where+ (INotify _ fd1 _ _ _) == (INotify _ fd2 _ _ _) = fd1 == fd2+ newtype Cookie = Cookie CUInt deriving (Eq,Ord) data FDEvent = FDEvent WD Masks CUInt{-Cookie-} (Maybe String) deriving (Eq, Show)@@ -79,7 +82,7 @@ { isDirectory :: Bool , maybeFilePath :: Maybe FilePath }- -- | A file was modified. @Modified isDiroctory file@+ -- | A file was modified. @Modified isDirectory file@ | Modified { isDirectory :: Bool , maybeFilePath :: Maybe FilePath@@ -123,7 +126,7 @@ } -- | A file was deleted. @Deleted isDirectory file@ | Deleted- { isDirecotry :: Bool+ { isDirectory :: Bool , filePath :: FilePath } -- | The file watched was deleted.@@ -183,7 +186,7 @@ return (INotify h fd em tid1 tid2) addWatch :: INotify -> [EventVariety] -> FilePath -> (Event -> IO ()) -> IO WatchDescriptor-addWatch inotify@(INotify h fd em _ _) masks fp cb = do+addWatch inotify@(INotify _ fd em _ _) masks fp cb = do is_dir <- doesDirectoryExist fp when (not is_dir) $ do file_exist <- doesFileExist fp@@ -195,9 +198,8 @@ Nothing (Just fp) let mask = joinMasks (map eventVarietyToMask masks)- em' <- takeMVar em wd <- withCString fp $ \fp_c ->- throwErrnoIfMinus1 "addWatch" $+ throwErrnoIfMinus1 "addWatch" $ c_inotify_add_watch (fromIntegral fd) fp_c mask let event = \e -> do when (OneShot `elem` masks) $@@ -208,8 +210,8 @@ Ignored -> rm_watch inotify wd _ -> return () cb e- putMVar em (Map.insert wd event em')- return (WatchDescriptor h wd)+ modifyMVar_ em $ \em' -> return (Map.insert wd event em')+ return (WatchDescriptor inotify wd) where eventVarietyToMask ev = case ev of@@ -233,8 +235,8 @@ OneShot -> inOneshot AllEvents -> inAllEvents -removeWatch :: INotify -> WatchDescriptor -> IO ()-removeWatch (INotify _ fd _ _ _) (WatchDescriptor _ wd) = do+removeWatch :: WatchDescriptor -> IO ()+removeWatch (WatchDescriptor (INotify _ fd _ _ _) wd) = do _ <- throwErrnoIfMinus1 "removeWatch" $ c_inotify_rm_watch (fromIntegral fd) wd return ()
+ tests/Utils.hs view
@@ -0,0 +1,55 @@+module Utils where++import Control.Concurrent.Chan+import Control.Exception++import System.Directory+import System.Environment+import System.Exit++import System.INotify++testName = do+ n <- getProgName+ return (n ++ "-playground")++withTempDir f = do+ path <- testName+ bracket+ ( createDirectory path >> return path )+ ( removeDirectoryRecursive )+ ( f )++withWatch inot events path action f =+ bracket+ ( addWatch inot events path action )+ removeWatch+ ( const f )++inTestEnviron events action f = do+ withTempDir $ \testPath -> do+ inot <- initINotify+ chan <- newChan+ withWatch inot events testPath (writeChan chan) $ do+ action testPath+ events <- getChanContents chan+ f events++(~=) :: Eq a => [a] -> [a] -> Bool+[] ~= _ = True+(x:xs) ~= (y:ys) = x == y && xs ~= ys+_ ~= _ = False++asMany :: [a] -> [a] -> [a]+asMany xs ys = take (length xs) ys++explainFailure expected reality = do+ putStrLn "Expected:"+ mapM_ (\x -> putStr "> " >> print x) expected+ putStrLn "But got:"+ mapM_ (\x -> putStr "< " >> print x) (asMany expected reality)+ testFailure++testFailure = exitFailure ++testSuccess = exitWith ExitSuccess
+ tests/test-all view
@@ -0,0 +1,31 @@+#!/bin/bash++GHC=ghc++if [[ -n $1 ]]; then+ GHC="$1"+ echo Using GHC: $GHC+fi++TESTS=( `ls test*.hs | cut -d. -f1` )++rm -rf *.o *.hi++for t in ${TESTS[@]}; do+ rm -rf $t{,.o,.hi}+ rm -rf $t-playground+ $GHC -v0 --make $t.hs -o $t+ echo -n Testing $t ...+ if [[ -x $t ]]; then+ ./$t+ exitCode=$?+ if [[ $exitCode == 0 ]]; then+ echo Success+ rm -rf $t{,.o,.hi}+ else+ echo Failure with exit code $exitCode+ fi+ else+ echo Compilation failed+ fi+done
+ tests/test001-list-dir-contents.hs view
@@ -0,0 +1,20 @@+module Main where++import Control.Monad++import System.Directory++import System.INotify as INotify++import Utils++main =+ inTestEnviron [Open, Close] getDirectoryContents $ \ events -> do+ when (expected ~= events)+ testSuccess+ explainFailure expected events++expected =+ [ Opened True Nothing+ , Closed True Nothing False+ ]
+ tests/test002-writefile.hs view
@@ -0,0 +1,24 @@+module Main where++import Control.Monad++import System.INotify as INotify++import Utils++write path = do+ writeFile (path ++ "/hello") ""+ -- actually writing any contents gives me two Modified+ +main =+ inTestEnviron [AllEvents] write $ \ events -> do+ when (expected ~= events)+ testSuccess+ explainFailure expected events++expected =+ [ Created False "hello"+ , Opened False (Just "hello")+ , Modified False (Just "hello")+ , Closed False (Just "hello") True+ ]
+ tests/test003-removefile.hs view
@@ -0,0 +1,35 @@+module Main where++import Control.Monad++import System.Directory++import System.INotify as INotify++import Utils++file = "hello"++write path = do+ writeFile (path ++ '/':file) ""++remove path = do+ removeFile (path ++ '/':file)++action path = do+ write path+ remove path+ +main =+ inTestEnviron [AllEvents] action $ \ events -> do+ when (expected ~= events)+ testSuccess+ explainFailure expected events++expected =+ [ Created False file+ , Opened False (Just file)+ , Modified False (Just file)+ , Closed False (Just file) True+ , Deleted False file+ ]
+ tests/test004-modify-file.hs view
@@ -0,0 +1,47 @@+module Main where++import Control.Exception+import Control.Monad++import System.Directory+import System.IO++import System.INotify as INotify++import Utils++file = "hello"++write path = do+ writeFile (path ++ '/':file) ""++modify path = do+ bracket+ (openFile (path ++ '/':file) AppendMode)+ (hClose)+ (\h -> hPutStr h "yarr!")++remove path = do+ removeFile (path ++ '/':file)++action path = do+ write path+ modify path+ remove path+ +main =+ inTestEnviron [AllEvents] action $ \ events -> do+ when (expected ~= events)+ testSuccess+ explainFailure expected events++expected =+ [ Created False file+ , Opened False (Just file)+ , Modified False (Just file)+ , Closed False (Just file) True+ , Opened False (Just file)+ , Modified False (Just file)+ , Closed False (Just file) True+ , Deleted False file+ ]
+ tests/test005-move-file.hs view
@@ -0,0 +1,46 @@+module Main where++import Data.Maybe++import Control.Monad++import System.Directory+import System.IO++import System.INotify as INotify++import Utils++file = "hello"+file2 = file ++ "2"++write path = do+ writeFile (path ++ '/':file) ""++move path = do+ renameFile (path ++ '/':file) (path ++ '/':file2)++remove path = do+ removeFile (path ++ '/':file2)++action path = do+ write path+ move path+ remove path+ +main =+ inTestEnviron [AllEvents] action $ \ events -> do+ let cookie = head [ c | MovedOut _ _ c <- events ]+ when (expected cookie ~= events)+ testSuccess+ explainFailure (expected cookie) events++expected cookie =+ [ Created False file+ , Opened False (Just file)+ , Modified False (Just file)+ , Closed False (Just file) True+ , MovedOut False file cookie+ , MovedIn False file2 cookie+ , Deleted False file2+ ]