add a flag indicating if an event was synthesized during initial dir scan
This commit is contained in:
parent
d3b9b32f21
commit
535d9e4998
2 changed files with 23 additions and 14 deletions
|
@ -18,7 +18,10 @@
|
||||||
- Thread 3: inotify internal
|
- Thread 3: inotify internal
|
||||||
- Used by haskell inotify library to ensure inotify event buffer is
|
- Used by haskell inotify library to ensure inotify event buffer is
|
||||||
- kept drained.
|
- kept drained.
|
||||||
- Thread 4: committer
|
- Thread 4: inotify initial scan
|
||||||
|
- A MVar lock is used to prevent other inotify handlers from running
|
||||||
|
- until this is complete.
|
||||||
|
- Thread 5: committer
|
||||||
- Waits for changes to occur, and runs the git queue to update its
|
- Waits for changes to occur, and runs the git queue to update its
|
||||||
- index, then commits.
|
- index, then commits.
|
||||||
-
|
-
|
||||||
|
|
|
@ -15,7 +15,11 @@ import qualified System.Posix.Files as Files
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
import Control.Exception (throw)
|
import Control.Exception (throw)
|
||||||
|
|
||||||
type Hook a = Maybe (a -> IO ())
|
{- A hook is passed some value to act on.
|
||||||
|
-
|
||||||
|
- The Bool is False when we're in the intial scan of a directory tree,
|
||||||
|
- rather than having received a genuine inotify event. -}
|
||||||
|
type Hook a = Maybe (a -> Bool -> IO ())
|
||||||
|
|
||||||
data WatchHooks = WatchHooks
|
data WatchHooks = WatchHooks
|
||||||
{ addHook :: Hook FilePath
|
{ addHook :: Hook FilePath
|
||||||
|
@ -31,7 +35,7 @@ data WatchHooks = WatchHooks
|
||||||
- made for different events.
|
- made for different events.
|
||||||
-
|
-
|
||||||
- Inotify is weak at recursive directory watching; the whole directory
|
- Inotify is weak at recursive directory watching; the whole directory
|
||||||
- tree must be walked and watches set explicitly for each subdirectory.
|
- tree must be scanned and watches set explicitly for each subdirectory.
|
||||||
-
|
-
|
||||||
- To notice newly created subdirectories, inotify is used, and
|
- To notice newly created subdirectories, inotify is used, and
|
||||||
- watches are registered for those directories. There is a race there;
|
- watches are registered for those directories. There is a race there;
|
||||||
|
@ -65,14 +69,14 @@ watchDir i dir ignored hooks
|
||||||
void (addWatch i watchevents dir handler)
|
void (addWatch i watchevents dir handler)
|
||||||
`catchIO` failedaddwatch
|
`catchIO` failedaddwatch
|
||||||
withLock lock $
|
withLock lock $
|
||||||
mapM_ walk =<< filter (not . dirCruft) <$>
|
mapM_ scan =<< filter (not . dirCruft) <$>
|
||||||
getDirectoryContents dir
|
getDirectoryContents dir
|
||||||
where
|
where
|
||||||
recurse d = watchDir i d ignored hooks
|
recurse d = watchDir i d ignored hooks
|
||||||
|
|
||||||
-- Select only inotify events required by the enabled
|
-- Select only inotify events required by the enabled
|
||||||
-- hooks, but always include Create so new directories can
|
-- hooks, but always include Create so new directories can
|
||||||
-- be walked.
|
-- be scanned.
|
||||||
watchevents = Create : addevents ++ delevents
|
watchevents = Create : addevents ++ delevents
|
||||||
addevents
|
addevents
|
||||||
| hashook addHook || hashook addSymlinkHook = [MoveIn, CloseWrite]
|
| hashook addHook || hashook addSymlinkHook = [MoveIn, CloseWrite]
|
||||||
|
@ -81,15 +85,15 @@ watchDir i dir ignored hooks
|
||||||
| hashook delHook || hashook delDirHook = [MoveOut, Delete]
|
| hashook delHook || hashook delDirHook = [MoveOut, Delete]
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
|
|
||||||
walk f = unless (ignored f) $ do
|
scan f = unless (ignored f) $ do
|
||||||
let fullf = indir f
|
let fullf = indir f
|
||||||
r <- catchMaybeIO $ getSymbolicLinkStatus fullf
|
r <- catchMaybeIO $ getSymbolicLinkStatus fullf
|
||||||
case r of
|
case r of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just s
|
Just s
|
||||||
| Files.isDirectory s -> recurse fullf
|
| Files.isDirectory s -> recurse fullf
|
||||||
| Files.isSymbolicLink s -> addSymlinkHook <@> f
|
| Files.isSymbolicLink s -> addSymlinkHook <@?> f
|
||||||
| Files.isRegularFile s -> addHook <@> f
|
| Files.isRegularFile s -> addHook <@?> f
|
||||||
| otherwise -> return ()
|
| otherwise -> return ()
|
||||||
|
|
||||||
-- Ignore creation events for regular files, which won't be
|
-- Ignore creation events for regular files, which won't be
|
||||||
|
@ -105,9 +109,9 @@ watchDir i dir ignored hooks
|
||||||
go (Closed { isDirectory = False, maybeFilePath = Just f }) =
|
go (Closed { isDirectory = False, maybeFilePath = Just f }) =
|
||||||
whenM (filetype Files.isRegularFile f) $
|
whenM (filetype Files.isRegularFile f) $
|
||||||
addHook <@> f
|
addHook <@> f
|
||||||
-- When a file or directory is moved in, walk it to add new
|
-- When a file or directory is moved in, scan it to add new
|
||||||
-- stuff.
|
-- stuff.
|
||||||
go (MovedIn { filePath = f }) = walk f
|
go (MovedIn { filePath = f }) = scan f
|
||||||
go (MovedOut { isDirectory = isd, filePath = f })
|
go (MovedOut { isDirectory = isd, filePath = f })
|
||||||
| isd = delDirHook <@> f
|
| isd = delDirHook <@> f
|
||||||
| otherwise = delHook <@> f
|
| otherwise = delHook <@> f
|
||||||
|
@ -124,9 +128,11 @@ watchDir i dir ignored hooks
|
||||||
|
|
||||||
hashook h = isJust $ h hooks
|
hashook h = isJust $ h hooks
|
||||||
|
|
||||||
h <@> f
|
runhook h f inscan
|
||||||
| ignored f = noop
|
| ignored f = noop
|
||||||
| otherwise = maybe noop (\a -> a $ indir f) (h hooks)
|
| otherwise = maybe noop (\a -> a (indir f) inscan) (h hooks)
|
||||||
|
h <@> f = runhook h f False
|
||||||
|
h <@?> f = runhook h f True
|
||||||
|
|
||||||
indir f = dir </> f
|
indir f = dir </> f
|
||||||
|
|
||||||
|
@ -141,10 +147,10 @@ watchDir i dir ignored hooks
|
||||||
Just hook -> tooManyWatches hook dir
|
Just hook -> tooManyWatches hook dir
|
||||||
| otherwise = throw e
|
| otherwise = throw e
|
||||||
|
|
||||||
tooManyWatches :: (String -> IO ()) -> FilePath -> IO ()
|
tooManyWatches :: (String -> Bool -> IO ()) -> FilePath -> IO ()
|
||||||
tooManyWatches hook dir = do
|
tooManyWatches hook dir = do
|
||||||
sysctlval <- querySysctl [Param maxwatches] :: IO (Maybe Integer)
|
sysctlval <- querySysctl [Param maxwatches] :: IO (Maybe Integer)
|
||||||
hook $ unlines $ basewarning : maybe withoutsysctl withsysctl sysctlval
|
hook (unlines $ basewarning : maybe withoutsysctl withsysctl sysctlval) False
|
||||||
where
|
where
|
||||||
maxwatches = "fs.inotify.max_user_watches"
|
maxwatches = "fs.inotify.max_user_watches"
|
||||||
basewarning = "Too many directories to watch! (Not watching " ++ dir ++")"
|
basewarning = "Too many directories to watch! (Not watching " ++ dir ++")"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue