Commits

Laurie Clark-Michalek  committed 1763dbf

Changed file monitor backend to fsnotify.

As fsnotify supports linux and windows also, this makes spy run on those
platforms (only tested on linux). The exported JSON format is slightly
different however, as fsnotify exposes the time the event was picked up
but not the "id" or "flags" that hfsevents does.

  • Participants
  • Parent commits a8634bc

Comments (1)

Files changed (2)

                             test-framework-hunit,
                             HUnit,
                             QuickCheck >= 2.4.0.1,
-                            hfsevents >= 0.1.3,
+                            fsnotify >= 0.0.4,
                             cmdargs >= 0.10,
                             filepath >= 1.3,
                             filemanip >= 0.3.6.2,
                             process >= 1.1,
                             json >= 0.7,
-                            directory >= 1.1
+                            directory >= 1.1,
+                            system-filepath >= 0.4.7,
+                            time >= 1.4.0.1
 
 executable  spy
   main-is:          Main.hs
   other-modules:    Spy.Watcher
   build-depends:
                     base < 5 && >= 3,
-                    hfsevents >= 0.1.3,
+                    fsnotify >= 0.0.4,
                     cmdargs >= 0.10,
                     filepath >= 1.3,
                     filemanip >= 0.3.6.2,
                     process >= 1.1,
                     json >= 0.7,
-                    directory >= 1.1
+                    directory >= 1.1,
+                    system-filepath >= 0.4.7,
+                    time >= 1.4.0.1
 
   ghc-options:
                     -Wall

File src/Spy/Watcher.hs

 ,containsHiddenPathElement
 ) where
 
-import System.OSX.FSEvents
+import System.FSNotify
 import System.Console.CmdArgs
 import System.Cmd
 import System.Exit
 import System.IO (stderr, hPrint)
 import System.FilePath.GlobPattern
 import System.FilePath (splitDirectories, takeFileName)
-import Control.Monad (unless)
-import Control.Exception (bracket)
+import Filesystem.Path.CurrentOS (encodeString, decodeString)
+import Data.Time.Clock(UTCTime)
 import Data.Maybe (fromMaybe, maybeToList)
-import Data.Bits
-import Data.Word
 import Text.JSON
 
 -- | The output format when Spy prints out changes to STDOUT
 
 -- | Register for FS events using the given Spy config.
 spy :: Spy -> IO String
-spy config = bracket
-  (eventStreamCreate [dir config] 1.0 True True True $ handleEvent config)
-  eventStreamDestroy
-  (\_ -> getLine)
+spy config = withManager $ \wm ->
+  watchDir wm (decodeString $ dir config)
+              (not . skipEvent config)
+              (handleEvent config) >>
+  getLine
 
 -- | Handle the FS event based on the current Spy run configuration
 handleEvent :: Spy -> Event -> IO ()
-handleEvent config@Run{..} event =
-        unless (skipEvent config event) $
+handleEvent Run{..} event =
         runCommand command pathAsArg >>=
             \exit -> case exit of
                 ExitSuccess     -> return ()
                             Nothing
                             else Just (eventPath event)
 
-handleEvent config@Watch{..} event =
-        unless (skipEvent config event) $
+handleEvent Watch{..} event =
         putStrLn $ (outputHandler $ fromMaybe Plain format) event
 
 -- =================================================================================
 outputHandler :: Format -> Printer
 outputHandler Json  = \event -> encode $ makeObj [
     ("path", showJSON $ eventPath event),
-    ("id", showJSON $ eventId event),
-    ("flags", showJSONs $ showEventFlags $ eventFlags event)]
+    ("time", showJSON . show $ eventTime event)]
 outputHandler Plain = eventPath
 
 
           skipNonMatchingGlob   = maybe False (not . matchesFile path) $ glob config
           path                  = eventPath event
 
+eventTime :: Event -> UTCTime
+eventTime (Added _ t) = t
+eventTime (Modified _ t) = t
+eventTime (Removed _ t) = t
+
+eventPath :: Event -> FilePath
+eventPath (Added fp _) = encodeString fp
+eventPath (Modified fp _) = encodeString fp
+eventPath (Removed fp _) = encodeString fp
 
 matchesFile :: FilePath -> GlobPattern -> Bool
 matchesFile path glob' = takeFileName path ~~ glob'
                       isHidden name' = case name' of
                                             (x:_)   -> x == '.'
                                             _       -> False
-
--- =================================================================================
--- The following code is taken from:
--- https://github.com/luite/hfsevents/blob/master/test/trace.hs
--- Copyright (c) 2012, Luite Stegeman
-showEventFlags :: Word64 -> [String]
-showEventFlags fl = map fst . filter hasFlag $ flagList
-  where hasFlag (_,f) = fl .&. f /= 0
-
-
-flagList :: [(String, Word64)]
-flagList = [ ("MustScanSubDirs"   , 0x00000001)
-           , ("UserDropped"       , 0x00000002)
-           , ("KernelDropped"     , 0x00000004)
-           , ("EventIdsWrapped"   , 0x00000008)
-           , ("HistoryDone"       , 0x00000010)
-           , ("RootChanged"       , 0x00000020)
-           , ("Mount"             , 0x00000040)
-           , ("Unmount"           , 0x00000080)
-           , ("ItemCreated"       , 0x00000100)
-           , ("ItemRemoved"       , 0x00000200)
-           , ("ItemInodeMetaMod"  , 0x00000400)
-           , ("ItemRenamed"       , 0x00000800)
-           , ("ItemModified"      , 0x00001000)
-           , ("ItemFinderInfoMod" , 0x00002000)
-           , ("ItemChangeOwner"   , 0x00004000)
-           , ("ItemXattrMod"      , 0x00008000)
-           , ("ItemIsFile"        , 0x00010000)
-           , ("ItemIsDir"         , 0x00020000)
-           , ("ItemIsSymlink"     , 0x00040000)
-           ]