streamly-fsnotify 1.0.1.0 → 1.1.0.0
raw patch · 4 files changed
+48/−47 lines, 4 filesdep +filepathdep −pathsPVP ok
version bump matches the API change (PVP)
Dependencies added: filepath
Dependencies removed: paths
API changes (from Hackage documentation)
- Streamly.FSNotify: type StopWatching m = m ()
+ Streamly.FSNotify: data StopWatching m
- Streamly.FSNotify: Added :: Path Absolute -> UTCTime -> FSEntryType -> Event
+ Streamly.FSNotify: Added :: FilePath -> UTCTime -> FSEntryType -> Event
- Streamly.FSNotify: Modified :: Path Absolute -> UTCTime -> FSEntryType -> Event
+ Streamly.FSNotify: Modified :: FilePath -> UTCTime -> FSEntryType -> Event
- Streamly.FSNotify: Other :: Path Absolute -> UTCTime -> Text -> Event
+ Streamly.FSNotify: Other :: FilePath -> UTCTime -> Text -> Event
- Streamly.FSNotify: Removed :: Path Absolute -> UTCTime -> FSEntryType -> Event
+ Streamly.FSNotify: Removed :: FilePath -> UTCTime -> FSEntryType -> Event
- Streamly.FSNotify: eventPath :: Event -> FsPath
+ Streamly.FSNotify: eventPath :: Event -> FilePath
- Streamly.FSNotify: hasExtension :: FileExt -> EventPredicate
+ Streamly.FSNotify: hasExtension :: FilePath -> EventPredicate
- Streamly.FSNotify: watchDirectory :: (IsStream t, MonadAsync m) => FsPath -> EventPredicate -> m (StopWatching m, t m Event)
+ Streamly.FSNotify: watchDirectory :: (IsStream t, MonadAsync m) => FilePath -> EventPredicate -> m (StopWatching m, t m Event)
- Streamly.FSNotify: watchDirectoryWith :: (IsStream t, MonadAsync m) => WatchConfig -> FsPath -> EventPredicate -> m (StopWatching m, t m Event)
+ Streamly.FSNotify: watchDirectoryWith :: (IsStream t, MonadAsync m) => WatchConfig -> FilePath -> EventPredicate -> m (StopWatching m, t m Event)
- Streamly.FSNotify: watchTree :: (IsStream t, MonadAsync m) => FsPath -> EventPredicate -> m (StopWatching m, t m Event)
+ Streamly.FSNotify: watchTree :: (IsStream t, MonadAsync m) => FilePath -> EventPredicate -> m (StopWatching m, t m Event)
- Streamly.FSNotify: watchTreeWith :: (IsStream t, MonadAsync m) => WatchConfig -> FsPath -> EventPredicate -> m (StopWatching m, t m Event)
+ Streamly.FSNotify: watchTreeWith :: (IsStream t, MonadAsync m) => WatchConfig -> FilePath -> EventPredicate -> m (StopWatching m, t m Event)
Files
- CHANGELOG.md +5/−0
- README.md +6/−9
- src/Streamly/FSNotify.hs +35/−36
- streamly-fsnotify.cabal +2/−2
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for streamly-fsnotify +## 1.1.0.0 -- 2020-05-27++* Use abstract newtype for `StopWatching`.+* Remove typed filepaths. Power-to-weight ratio was too low.+ ## 1.0.1.0 -- 2020-05-27 * George Thomas takes over as maintainer. Metadata changes.
README.md view
@@ -1,5 +1,3 @@-# ``streamly-fsnotify``- ## What's the deal with this library? [``streamly``][1] is an undoubtedly awesome library - [fast][2], flexible, and@@ -15,26 +13,26 @@ {-# LANGUAGE LambdaCase #-} +import System.FilePath ((</>)) import Streamly.FSNotify (EventPredicate, hasExtension, isDirectory, invert, isDeletion, conj, watchTree)-import System.Path (FsPath, FileExt(FileExt), fromFilePath) import qualified Streamly.Prelude as SP -- conj -> both must be true -- invert -> true when the argument would be false and vice versa isCSourceFile :: EventPredicate-isCSourceFile = hasExtension (FileExt "c") `conj` invert isDirectory+isCSourceFile = hasExtension "c" `conj` invert isDirectory notDeletion :: EventPredicate notDeletion = invert isDeletion -srcPath :: FsPath-srcPath = fromFilePath "/home/koz/c-project"+srcPath :: FilePath+srcPath = "home" </> "koz" </> "c-project" -- first value given by watchTree stops the watcher -- we don't use it here, but if you want to, just call it main :: IO () main = do- (_, stream) <- watchTree srcPath (isCSourceFile `conj` notDeletion)+ (_, stream) <- watchTree srcPath $ isCSourceFile `conj` notDeletion SP.drain . SP.mapM go $ stream where go = \case@@ -48,10 +46,9 @@ * Cross-platform - should work anywhere both ``streamly`` and ``fsnotify`` do. * Efficient (event-driven, so won't shred your CPU or load your RAM). * Able to do one-level and recursive watching.+* Compositional and principled treatment of event filtering predicates. * Extensive set of filtering predicates, so you don't have to see events you don't care about!-* Compositional and principled treatment of file paths and event filtering- predicates. ## Sounds good? Can I use it?
src/Streamly/FSNotify.hs view
@@ -12,26 +12,26 @@ > {-# LANGUAGE LambdaCase #-} >+> import System.FilePath ((</>)) > import Streamly.FSNotify (EventPredicate, hasExtension, isDirectory, invert, isDeletion, conj, watchTree)-> import System.Path (FsPath, FileExt(FileExt), fromFilePath) > import qualified Streamly.Prelude as SP > > -- conj -> both must be true > -- invert -> true when the argument would be false and vice versa > isCSourceFile :: EventPredicate-> isCSourceFile = hasExtension (FileExt "c") `conj` invert isDirectory+> isCSourceFile = hasExtension "c" `conj` invert isDirectory > > notDeletion :: EventPredicate > notDeletion = invert isDeletion >-> srcPath :: FsPath-> srcPath = fromFilePath "/home/koz/c-project"+> srcPath :: FilePath+> srcPath = "home" </> "koz" </> "c-project" > > -- first value given by watchTree stops the watcher > -- we don't use it here, but if you want to, just call it > main :: IO () > main = do-> (_, stream) <- watchTree srcPath (isCSourceFile `conj` notDeletion)+> (_, stream) <- watchTree srcPath $ isCSourceFile `conj` notDeletion > SP.drain . SP.mapM go $ stream > where > go = \case@@ -41,7 +41,7 @@ -} module Streamly.FSNotify ( -- * Basic types- FSEntryType(..), Event(..), StopWatching,+ FSEntryType(..), Event(..), StopWatching(stopWatching), eventPath, eventTime, eventFSEntry, -- * Events and predicates EventPredicate(..),@@ -58,7 +58,7 @@ import Data.Text (Text, pack) import Data.Time.Clock (UTCTime) import Streamly (IsStream, MonadAsync)-import System.Path (Path, FsPath(..), FileExt, Absolute, isExtensionOf, toFilePath, makeAbsolute, fromAbsoluteFilePath)+import System.FilePath (isExtensionOf) import qualified Streamly.Prelude as SP import qualified System.FSNotify as FSN@@ -70,22 +70,22 @@ -- | A file system notification. data Event- = Added (Path Absolute) UTCTime FSEntryType -- ^ Creation event- | Modified (Path Absolute) UTCTime FSEntryType -- ^ Modification event- | Removed (Path Absolute) UTCTime FSEntryType -- ^ Deletion event- | Other (Path Absolute) UTCTime Text -- ^ Some other kind of event+ = Added FilePath UTCTime FSEntryType -- ^ Creation event+ | Modified FilePath UTCTime FSEntryType -- ^ Modification event+ | Removed FilePath UTCTime FSEntryType -- ^ Deletion event+ | Other FilePath UTCTime Text -- ^ Some other kind of event deriving (Eq, Show) --- | A function, which, when executed, stops a file system watch.-type StopWatching m = m ()+-- | An object, which, when executed with 'stopWatching', stops a file system watch.+newtype StopWatching m = StopWatching { stopWatching :: m () } -- | Helper to retrieve the file path associated with an event.-eventPath :: Event -> FsPath+eventPath :: Event -> FilePath eventPath = \case- Added p _ _ -> FsPath p- Modified p _ _ -> FsPath p- Removed p _ _ -> FsPath p- Other p _ _ -> FsPath p+ Added p _ _ -> p+ Modified p _ _ -> p+ Removed p _ _ -> p+ Other p _ _ -> p -- | Helper to retrieve an event's timestamp. eventTime :: Event -> UTCTime@@ -140,11 +140,11 @@ -- | The trivial predicate (allows any event through). everything :: EventPredicate-everything = EventPredicate . const $ True+everything = EventPredicate $ const True -- | The null predicate (allows no events through). nothing :: EventPredicate-nothing = EventPredicate . const $ False+nothing = EventPredicate $ const False -- | Allows through events that are caused by directories. -- Note that this will assume that non-\'basic\' events (that is, not creations, modifications or deletions) do not stem@@ -157,8 +157,8 @@ -- | Allows through events triggered by file system entries with a specific -- extension.-hasExtension :: FileExt -> EventPredicate-hasExtension fe = EventPredicate $ isExtensionOf fe . \case+hasExtension :: FilePath -> EventPredicate+hasExtension fe = EventPredicate $ (fe `isExtensionOf`) . \case Added p _ _ -> p Modified p _ _ -> p Removed p _ _ -> p@@ -196,20 +196,20 @@ {- Watchers -} -- | Watch a given directory, but only at one level (thus, subdirectories will __not__ be watched recursively).-watchDirectory :: (IsStream t, MonadAsync m) => FsPath -> EventPredicate -> m (StopWatching m, t m Event)+watchDirectory :: (IsStream t, MonadAsync m) => FilePath -> EventPredicate -> m (StopWatching m, t m Event) watchDirectory = watch FSN.watchDirChan FSN.defaultConfig -- | As 'watchDirectory', but with a specified set of watch options. watchDirectoryWith :: (IsStream t, MonadAsync m) =>- FSN.WatchConfig -> FsPath -> EventPredicate -> m (StopWatching m, t m Event)+ FSN.WatchConfig -> FilePath -> EventPredicate -> m (StopWatching m, t m Event) watchDirectoryWith = watch FSN.watchDirChan -- | Watch a given directory recursively (thus, subdirectories will also have their contents watched).-watchTree :: (IsStream t, MonadAsync m) => FsPath -> EventPredicate -> m (StopWatching m, t m Event)+watchTree :: (IsStream t, MonadAsync m) => FilePath -> EventPredicate -> m (StopWatching m, t m Event) watchTree = watch FSN.watchTreeChan FSN.defaultConfig -- | As 'watchTree', but with a specified set of watch options.-watchTreeWith :: (IsStream t, MonadAsync m) => FSN.WatchConfig -> FsPath -> EventPredicate -> m (StopWatching m, t m Event)+watchTreeWith :: (IsStream t, MonadAsync m) => FSN.WatchConfig -> FilePath -> EventPredicate -> m (StopWatching m, t m Event) watchTreeWith = watch FSN.watchTreeChan @@ -217,22 +217,21 @@ watch :: (IsStream t, MonadAsync m) => (FSN.WatchManager -> FilePath -> FSN.ActionPredicate -> FSN.EventChannel -> IO FSN.StopListening) ->- FSN.WatchConfig -> FsPath -> EventPredicate -> m (StopWatching m, t m Event)+ FSN.WatchConfig -> FilePath -> EventPredicate -> m (StopWatching m, t m Event) watch f conf p predicate = do- manager <- liftIO . FSN.startManagerConf $ conf- fp <- toFilePath <$> liftIO (makeAbsolute p)+ manager <- liftIO $ FSN.startManagerConf conf let pred' = runPredicate predicate . mungeEvent chan <- liftIO newChan- stop <- liftIO $ f manager fp pred' chan- let reallyStop = liftIO stop >> liftIO (FSN.stopManager manager)- pure (reallyStop, SP.repeatM . liftIO . fmap mungeEvent $ readChan chan)+ stop <- liftIO $ f manager p pred' chan+ let reallyStop = StopWatching $ liftIO stop >> liftIO (FSN.stopManager manager)+ pure (reallyStop, SP.repeatM $ liftIO $ mungeEvent <$> readChan chan) mungeEvent :: FSN.Event -> Event mungeEvent = \case- FSN.Added p t b-> Added (fromAbsoluteFilePath p) t (isDir b)- FSN.Modified p t b-> Modified (fromAbsoluteFilePath p) t (isDir b)- FSN.Removed p t b-> Modified (fromAbsoluteFilePath p) t (isDir b)- FSN.Unknown p t s-> Other (fromAbsoluteFilePath p) t (pack s)+ FSN.Added p t b -> Added p t (isDir b)+ FSN.Modified p t b -> Modified p t (isDir b)+ FSN.Removed p t b -> Modified p t (isDir b)+ FSN.Unknown p t s -> Other p t (pack s) isDir :: Bool -> FSEntryType isDir = bool NotDir Dir
streamly-fsnotify.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: streamly-fsnotify-version: 1.0.1.0+version: 1.1.0.0 synopsis: Folder watching as a Streamly stream. description: Provides Streamly streams for both single-level and recursive folder watching.@@ -20,8 +20,8 @@ Streamly.FSNotify build-depends: base >= 4.9 && < 5,+ filepath ^>= 1.4.2.1, fsnotify ^>= 0.3.0.1,- paths ^>= 0.2.0.0, semirings ^>= 0.5.2, streamly ^>= 0.7.0, text ^>= 1.2.3.0,