packages feed

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 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 +[![hackage](https://img.shields.io/hackage/v/reflex-fsnotify.svg)](https://hackage.haskell.org/package/reflex-fsnotify) [![hackage-ci](https://matrix.hackage.haskell.org/api/v2/packages/reflex-fsnotify/badge)](https://matrix.hackage.haskell.org/#/package/reflex-fsnotify) [![travis-ci](https://api.travis-ci.org/reflex-frp/reflex-fsnotify.svg?branch=develop)](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