packages feed

fswatcher 0.1.3 → 0.2.0

raw patch · 2 files changed

+35/−18 lines, 2 filesdep +optparse-applicativedep +regex-pcre-builtin

Dependencies added: optparse-applicative, regex-pcre-builtin

Files

fswatcher.cabal view
@@ -1,7 +1,7 @@ name:               fswatcher category:           Tools build-type:         Simple-version:            0.1.3+version:            0.2.0 synopsis:           Watch a file/directory and run a command when it's modified description:        A simple program that watches a file or a directory and                     runs a given command whenever the file or a file within the@@ -23,6 +23,8 @@                    , fsnotify        >= 0.1                    , system-filepath >= 0.4                    , directory       >= 1.2+                   , optparse-applicative >= 0.11+                   , regex-pcre-builtin   >= 0.94     ghc-options:     -Wall     main-is:         fswatcher.hs 
fswatcher.hs view
@@ -1,34 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+ import System.IO (hPutStrLn, stderr) import System.Posix.Files (getFileStatus, isDirectory)-import System.Environment (getArgs, getProgName) import System.Directory (canonicalizePath, getCurrentDirectory) import Filesystem.Path ((</>), directory) import Filesystem.Path.CurrentOS (decodeString, encodeString) import Data.String (fromString) import System.FSNotify (Event (..), StopListening, WatchManager, startManager,-       stopManager, watchTree, watchDir)-import System.Exit (ExitCode (..), exitSuccess, exitFailure)+       stopManager, watchTree, watchDir, eventPath)+import System.Exit (ExitCode (..), exitSuccess) import System.Process (createProcess, proc, waitForProcess)-import Control.Monad (void, when)+import Control.Monad (void) import System.Posix.Signals (installHandler, Handler(Catch), sigINT, sigTERM) import Control.Concurrent (forkIO, killThread) import Control.Concurrent.MVar+import Text.Regex.PCRE+import Options.Applicative +import Opts+ data FileType = File | Directory deriving Eq  -- Watches a file or directory and whenever a “modified” event is registered we -- put () in the MVar that acts as a run trigger. `tryPutMVar` is used to avoid -- re-running the command many times if the file/dir is changed more than once -- while the command is already running.-watch :: FileType -> WatchManager -> String -> MVar () -> IO StopListening-watch filetype m path trigger =+watch :: FileType -> WatchManager -> String -> MVar () -> WatchOpt -> IO StopListening+watch filetype m path trigger opt =   let watchFun = case filetype of-                   Directory -> watchTree m path (const True)+                   Directory -> watchTree m path (matchFiles opt)                    File      -> watchDir  m (encodeString $ directory $ decodeString path) isThisFile    in watchFun (\_ -> void $ tryPutMVar trigger ())    where isThisFile (Modified p _) = p == fromString path         isThisFile _              = False+        matchFiles :: WatchOpt -> Event -> Bool+        matchFiles wo event = let p = eventPath event+                                  includes = includePath wo+                                  excludes = excludePath wo+                              in+                                (null includes || p =~ includePath wo)+                                && (null excludes || not (p =~ excludePath wo))  runCmd :: String -> [String] -> MVar () -> IO () runCmd cmd args trigger = do@@ -41,13 +53,12 @@                        ExitFailure n -> "Process returned " ++ show n   runCmd cmd args trigger -main :: IO ()-main = do-  argv <- getArgs-  when (length argv < 2) $ getProgName >>= usage >> exitFailure+runWatch :: WatchOpt -> IO ()+runWatch opt = do -  let [path,cmd]  = take 2 argv-  let args = drop 2 argv+  let path = watchPath opt+  let cmd = head $ actionCmd opt+  let args = drop 1 $ actionCmd opt    m <- startManager @@ -65,7 +76,7 @@    runTrigger <- newEmptyMVar   runThread <- forkIO $ runCmd cmd args runTrigger-  stopWatcher <- watch filetype m canonicalPath runTrigger+  stopWatcher <- watch filetype m canonicalPath runTrigger opt    -- Calculate the full path in order to print the "real" file when watching a   -- path with one or more symlinks.@@ -83,6 +94,10 @@   stopManager m   killThread runThread   exitSuccess-    where usage n = hPutStrLn stderr $ "Usage: " ++ n-                             ++ " <file/directory to watch>"-                             ++ " <command to run> [arguments for command]"++main :: IO ()+main = execParser opts >>= runWatch+  where+    opts = info (helper <*> watchOpt)+      ( fullDesc+     <> progDesc "monitors a file or a directory for changes and runs a given command.")