reflex-fsnotify 0.1.0.0 → 0.2.0.0
raw patch · 4 files changed
+85/−5 lines, 4 filesdep +containersdep +directorydep +filepathPVP ok
version bump matches the API change (PVP)
Dependencies added: containers, directory, filepath
API changes (from Hackage documentation)
+ Reflex.FSNotify: listDirectories :: FilePath -> IO (Set FilePath)
+ Reflex.FSNotify: watchDir :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m)) => WatchConfig -> Event t FilePath -> ActionPredicate -> m (Event t FSEvent)
+ Reflex.FSNotify: watchDirectoryTree :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m)) => WatchConfig -> Event t FilePath -> ActionPredicate -> m (Event t FSEvent)
+ Reflex.FSNotify: watchTree :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m)) => WatchConfig -> Event t FilePath -> ActionPredicate -> m (Event t FSEvent)
+ Reflex.FSNotify: wrapWatch :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m)) => (WatchManager -> FilePath -> Action -> IO a) -> WatchConfig -> Event t FilePath -> m (Event t FSEvent)
Files
- ChangeLog.md +6/−0
- README.md +2/−0
- reflex-fsnotify.cabal +5/−2
- src/Reflex/FSNotify.hs +72/−3
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for reflex-fsnotify +## 0.2.0.0++* Deprecate `watchDirectory`+* Add `watchDir` and `watchTree` corresponding to the functions in `System.FSNotify`+* Add `watchDirectoryTree`, an alternative to `watchTree` that tries to break symlink cycles+ ## 0.1.0.0 * Initial release containing `watchDirectory`.
README.md view
@@ -1,3 +1,5 @@ # reflex-fsnotify +[](https://hackage.haskell.org/package/reflex-fsnotify) [](https://matrix.hackage.haskell.org/#/package/reflex-fsnotify) [](https://travis-ci.org/reflex-frp/reflex-fsnotify)+ Watch directories for changes using a functional-reactive interface!
reflex-fsnotify.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: reflex-fsnotify-version: 0.1.0.0+version: 0.2.0.0 synopsis: reflex-frp interface for watching files description: Receive FRP events whenever files change. bug-reports: https://github.com/reflex-frp/reflex-fsnotify/issues@@ -13,11 +13,14 @@ build-type: Simple extra-source-files: ChangeLog.md README.md-tested-with: GHC ==8.6.5 || ==8.4.4+tested-with: GHC ==8.6.5 library exposed-modules: Reflex.FSNotify build-depends: base >=4.10 && <4.13+ , containers >= 0.6 && < 0.7+ , directory >= 1.3 && < 1.4+ , filepath >= 1.4 && < 1.5 , fsnotify >= 0.3 && < 0.4 , reflex >= 0.5 && < 0.7 hs-source-dirs: src
src/Reflex/FSNotify.hs view
@@ -4,7 +4,14 @@ -} {-# LANGUAGE FlexibleContexts #-}-module Reflex.FSNotify where+module Reflex.FSNotify+ ( watchDirectory+ , watchDir+ , watchTree+ , wrapWatch+ , listDirectories+ , watchDirectoryTree+ ) where import Control.Concurrent import Control.Monad@@ -12,16 +19,78 @@ import Reflex import qualified System.FSNotify as FS +import Data.Set (Set)+import qualified Data.Set as Set+import System.Directory+import System.FilePath ((</>))++-- A type synonym to disambiguate Reflex 'Event's from 'System.FSNotify.Event'+type FSEvent = FS.Event+ -- | Watch a directory for changes+{-# DEPRECATED watchDirectory "Use `watchDir cfg path (const True)` instead" #-} watchDirectory :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m)) => FS.WatchConfig -> Event t FilePath -> m (Event t FS.Event)-watchDirectory cfg path =+watchDirectory cfg path = watchDir cfg path (const True)++wrapWatch+ :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))+ => (FS.WatchManager -> FilePath -> FS.Action -> IO a)+ -> FS.WatchConfig+ -> Event t FilePath+ -> m (Event t FSEvent)+wrapWatch f cfg path = performEventAsync $ ffor path $ \p cb -> liftIO $ void $ forkIO $ FS.withManagerConf cfg $ \mgr -> do- _ <- FS.watchTree mgr p (const True) cb+ _ <- f mgr p cb -- FS.watchTree mgr p (const True) cb forever $ threadDelay 1000000 +watchDir+ :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))+ => FS.WatchConfig+ -> Event t FilePath+ -> FS.ActionPredicate+ -> m (Event t FSEvent)+watchDir cfg path evFilter = wrapWatch (\mgr p -> FS.watchDir mgr p evFilter) cfg path +watchTree+ :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))+ => FS.WatchConfig+ -> Event t FilePath+ -> FS.ActionPredicate+ -> m (Event t FSEvent)+watchTree cfg path evFilter = wrapWatch (\mgr p -> FS.watchTree mgr p evFilter) cfg path++listDirectories+ :: FilePath+ -> IO (Set FilePath)+listDirectories start = do+ start' <- canonicalizePath start+ Set.insert start' <$> listDirectories' Set.empty start'+ where+ listDirectories' :: Set FilePath -> FilePath -> IO (Set FilePath)+ listDirectories' seen dir0 = do+ let canonicalize p = canonicalizePath $ dir0 </> p+ contents <- mapM canonicalize =<< listDirectory dir0+ dirs <- filterM doesDirectoryExist contents+ let newDirs = filter (not . flip Set.member seen) dirs+ newSeen = Set.union seen $ Set.fromList newDirs+ allDirs <- mapM (listDirectories' newSeen) newDirs+ return $ Set.unions $ Set.fromList dirs : allDirs++-- | Like 'watchTree' except that it tries to avoid symlink loops and calls+-- 'watchDir' on each directory found+watchDirectoryTree+ :: (Reflex t, TriggerEvent t m, PerformEvent t m, MonadIO (Performable m))+ => FS.WatchConfig+ -> Event t FilePath+ -> FS.ActionPredicate+ -> m (Event t FSEvent)+watchDirectoryTree cfg root evFilter =+ let f mgr p cb = do+ dirs <- listDirectories p+ mapM_ (\dir -> FS.watchDir mgr dir evFilter cb) dirs+ in wrapWatch f cfg root