on bb74cdd help sign in
209 lines 7.3 kB history raw
1-- |
2-- Module : Streamly.FileSystem.Event
3-- Copyright : (c) 2020 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : pre-release
7-- Portability : GHC
8--
9-- File system event notification API portable across Linux, macOS and Windows
10-- platforms.
11--
12-- For platform specific API please see the following modules:
13--
14-- * "Streamly.Internal.FileSystem.Event.Darwin"
15-- * "Streamly.Internal.FileSystem.Event.Linux"
16-- * "Streamly.Internal.FileSystem.Event.Windows"
18module Streamly.Internal.FileSystem.Event
19 (
20 -- * Creating a Watch
22 watch
23 , watchRecursive
25 -- * Handling Events
26 , Event
27 , getAbsPath
29 -- ** Item CRUD events
30 , isCreated
31 , isDeleted
32 , isMoved
33 , isModified
35 -- ** Exception Conditions
36 , isEventsLost
38 -- ** Debugging
39 , showEvent
40 )
41where
43import Data.List.NonEmpty (NonEmpty)
44import Data.Word (Word8)
45import Streamly.Internal.Data.Array.Foreign (Array)
46import Streamly.Prelude (SerialT)
48#if defined(CABAL_OS_DARWIN)
49import Streamly.Internal.FileSystem.Event.Darwin (Event)
50import qualified Streamly.Internal.FileSystem.Event.Darwin as Event
51#elif defined(CABAL_OS_LINUX)
52import Streamly.Internal.FileSystem.Event.Linux (Event)
53import qualified Streamly.Internal.FileSystem.Event.Linux as Event
54#elif defined(CABAL_OS_WINDOWS)
55import Streamly.Internal.FileSystem.Event.Windows (Event)
56import qualified Streamly.Internal.FileSystem.Event.Windows as Event
57#else
58#error "FS Events not supported on this platform"
59#endif
61-- XXX Ensure that defaultConfig is the same for all platforms.
62--
63-- XXX Ensure that equivalent events are generated on all platforms when same
64-- operations are done. Document any differences in behavior on different
65-- platforms. Any events that are not common to all platforms should be
66-- filtered out.
67--
68-- XXX Only need to set common event types for macOS/Linux/Windows
69-- XXX write a test, that generates all types of events that can possibly
70-- occur on each platform. Then create a common test that only checks
71-- for the common subset of those.
73-------------------------------------------------------------------------------
74-- Creating a watch
75-------------------------------------------------------------------------------
77-- macOS and Windows seem to do a path level watch i.e. they watch the path
78-- rather than the underlying inode, possibly they can map the inode back to a
79-- path?. On Linux we cannot keep watching a watch root if the inode it is
80-- pointing to has moved. However, the inode continues to be watched in this
81-- case instead of the path, which is not the case for macOS.
82--
83-- To make the behavior same for all platforms, for the Linux case we will have
84-- to stop watching the inode if it moves from under the path
85-- (setUnwatchMoved). And on macOS we can stop watching a path if the inode
86-- under it changes i.e. just filter out events for that path.
87--
88-- Also, to make the behavior of Linux same as macOS we need to set
89-- setFollowSymLinks on Linux.
91-- XXX Verify all the cases mentioned below using test cases.
93-- | Start monitoring a list of file system paths for file system events. The
94-- paths could be files or directories. Monitoring starts from the current
95-- time onwards. The paths are specified as UTF-8 encoded 'Array' of 'Word8'.
96--
97-- If a watch root is a symbolic link then the target of the link is watched.
98-- Fails if the watched path does not exist. If the user does not have
99-- permissions (specific permissions?) on the watch root then no events are
100-- generated. No events are generated if the watch root itself is renamed or
101-- deleted.
102--
103-- Note: not yet implemented on macOS, use watchRecursive instead.
104--
105-- /Pre-release/
106--
107watch :: NonEmpty (Array Word8) -> SerialT IO Event
108watch = Event.watch
110-- | Like 'watch' except that if a watched path is a directory the whole
111-- directory tree under it is watched recursively.
112--
113-- On Linux 'watchRecursive' may be more expensive than 'watch'.
114--
115-- /Pre-release/
116--
117watchRecursive :: NonEmpty (Array Word8) -> SerialT IO Event
118watchRecursive = Event.watchRecursive
120-------------------------------------------------------------------------------
121-- Handling Events
122-------------------------------------------------------------------------------
124-- | Get the absolute path of the file system object for which the event is
125-- generated. The path is a UTF-8 encoded array of bytes.
126--
127-- /Pre-release/
128--
129getAbsPath :: Event -> Array Word8
130getAbsPath = Event.getAbsPath
132-- | Determine whether the event indicates creation of an object within the
133-- monitored path. This event is generated when any file system object is
134-- created.
135--
136-- For hard links the behavior is different on different operating systems. On
137-- macOS hard linking does not generate a create event, it generates an
138-- 'isInodeAttrsChanged' event on the directory instead. On Linux and Windows
139-- hard linking generates a create event.
140--
141-- /Pre-release/
142--
143isCreated :: Event -> Bool
144isCreated = Event.isCreated
146-- XXX To make the behavior consistent, can we block the event on watch root on
147-- macOS?
148--
149-- | Determine whether the event indicates deletion of an object within the
150-- monitored path. On Linux and Windows hard link deletion generates a delete
151-- event.
152--
153-- On Linux and Windows, this event does not occur when the watch root itself
154-- is deleted. On macOS it occurs on deleting the watch root when it is not a
155-- symbolic link.
156--
157-- See also 'isRootDeleted' event for Linux.
158--
159-- /Pre-release/
160--
161isDeleted :: Event -> Bool
162isDeleted = Event.isDeleted
164-- | Determine whether the event indicates rename of an object within the
165-- monitored path. This event is generated when an object is renamed within the
166-- watched directory or if it is moved out of or in the watched directory.
167-- Moving hard links is no different than other types of objects.
168--
169-- /Pre-release/
170--
171isMoved :: Event -> Bool
172isMoved = Event.isMoved
174-- XXX Make the Windows behavior consistent with other platforms by removing
175-- the event from directories.
176--
177-- | Determine whether the event indicates modification of an object within the
178-- monitored path. This event is generated on file modification on all
179-- platforms.
180--
181-- On Linux and macOS this event is never generated for directories. On
182-- Windows (in recursive watch mode) this event is generated for directories as
183-- well when an object is created in or deleted from the directory.
184--
185-- /Pre-release/
186--
187isModified :: Event -> Bool
188isModified = Event.isModified
190-- | An event that indicates that some events before this may have been lost,
191-- therefore, we need to take some recovery action.
192--
193-- /Pre-release/
194--
195isEventsLost :: Event -> Bool
196isEventsLost = Event.isEventsLost
198-------------------------------------------------------------------------------
199-- Debugging
200-------------------------------------------------------------------------------
202-- | Convert an 'Event' record to a String representation. Note that the output
203-- of this function may be different on different platforms because it may
204-- contain platform specific details.
205--
206-- /Internal/
207--
208showEvent :: Event -> String
209showEvent = Event.showEvent