Skip to content

Instantly share code, notes, and snippets.

@otruffer
Created November 28, 2016 07:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save otruffer/2d3a58be98ef4cbad4407c9ea53bf5bc to your computer and use it in GitHub Desktop.
Save otruffer/2d3a58be98ef4cbad4407c9ea53bf5bc to your computer and use it in GitHub Desktop.
#!/usr/bin/env stack
-- stack runghc --resolver lts-7.10 --install-ghc --package fsnotify
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Text.IO as T
import System.FSNotify
import Control.Concurrent (threadDelay, Chan, forkIO, killThread)
import Control.Concurrent.Chan (newChan, readChan, getChanContents)
import Control.Monad (forever)
import System.Environment (getArgs)
import System.Process (readProcess, readCreateProcessWithExitCode, readCreateProcess, shell, cwd)
main =
-- start watching job in the background.
withManager $ \mgr -> do
args <- getArgs
dir <- return $ args !! 0 -- 1 st argument is the Directory we watch
cmd <- return $ args !! 1 -- 2 nd argument is th command we execute
eventChannel <- newChan -- we will watch a channel to decide what to do (this will fork a thread)
watchTreeChan -- we watch a whole tree with a channel
mgr -- The manager
dir -- The directory
(const True) -- The pre decider if we want an event or not
eventChannel -- The event Channel
putStrLn $ "watching directory: " ++ dir
putStrLn $ "executing command: " ++ cmd
forkIO $ channelWatcher eventChannel cmd -- we fork a thread to watch the channel
forever $ threadDelay 1000000 -- sleep forever. otherwise the program terminates here.
channelWatcher :: Chan Event -> String -> IO ()
channelWatcher channel cmd = forever $ do
readChan channel -- This will block until the first event. We don't need the result.
executeCommand cmd -- We execute the command
putStrLn "Comand executed successfully" -- Everythings done
threadId <- forkIO $ endlessConsumer channel -- We consume and throw away everything that comes in...
threadDelay (1000 * 1000) -- For one second
killThread threadId -- Then we stop throwing stuff away.
executeCommand :: String-> IO ()
executeCommand cmd = do
(_, stdout, stderr) <- readCreateProcessWithExitCode (shell cmd) "" -- execute the command and output the result
putStrLn stdout
putStrLn stderr
endlessConsumer :: Chan Event -> IO () -- consumer that just throws away everything.
endlessConsumer channel = forever $ do
readChan channel >>= throwAwayEvent
throwAwayEvent _ = return ()
@otruffer
Copy link
Author

Haskell Script

A short haskell script that listens for filechanges in a path and executes a command if something in the path changes. It has a buffer of one second. After the execution of a command it waits for 1 second before re-executing the command. Changes that happen in this one second buffer are thrown away.

If you want to rebuild your stack project on changes use:

./listen-and-repeat.hs ./src "stack build && stack exec my-project-exe"

needs:

  • stack installed
  • chmod +x

todos:

  • message if args != 2
  • maybe color depending on command output
  • maybe redo command if change came in during the execution process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment