-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMain.hs
More file actions
157 lines (124 loc) · 4.06 KB
/
Copy pathMain.hs
File metadata and controls
157 lines (124 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import Control.Monad
import System.Console.GetOpt
import System.Directory
import System.Environment (getArgs)
import System.Exit
import System.INotify
import System.IO
import System.Process
data Config =
Config
{ confExecFile :: FilePath
, confWorking :: Bool
} deriving (Show,Read)
-- Options
data Options =
Options
{ optUsage :: Bool
, optExecFile :: FilePath
, optWatchDir :: FilePath
} deriving (Show)
options :: [OptDescr (Options -> IO Options)]
options =
[ Option "?" ["help"] (NoArg runUsage) "Show usage/help"
, Option "f" ["execfile"] (ReqArg setExecFile "execfile") "The file to read execution commands from"
, Option "d" ["watchdir"] (ReqArg setWatchDir "watchdir") "The directory to observe for changes"
]
defaultOptions = Options { optUsage = False
, optExecFile = []
, optWatchDir = []
}
runUsage opt = return opt { optUsage = True }
setExecFile x opt = return opt { optExecFile = x }
setWatchDir x opt = return opt { optWatchDir = x }
showUsage :: IO ()
showUsage = do
let header = "Usage: continuous-hs [OPTIONS...]"
putStrLn $ usageInfo header options
exitFailure
main :: IO ()
main = do
args <- getArgs
let (actions, nonOpts, msgs) = getOpt RequireOrder options args
opts <- foldl (>>=) (return defaultOptions) $ reverse actions
if optUsage opts || optExecFile opts == [] || optWatchDir opts == []
then showUsage
else runWorker opts
-- /OPTIONS
runWorker
:: Options
-> IO ()
runWorker opts = do
let dir = optWatchDir opts
let execFile = optExecFile opts
putStrLn $ "Exec file: " ++ execFile
putStrLn $ "Watching directory: " ++ dir
fileExists <- doesFileExist execFile
when (not fileExists) $ do
putStrLn $ "Exec file does not exist!"
putStrLn "Exiting"
exitFailure
dirExists <- doesDirectoryExist dir
when (not dirExists) $ do
putStrLn $ "Watch directory does not exist!"
putStrLn "Exiting"
exitFailure
let config = Config execFile False
runThread config dir
runThread config dir = do
config <- newTVarIO config
n <- initINotify
putStrLn "Press <Enter> to exit"
putStrLn n
wd <- addWatch n
[ Modify, CloseWrite, Create, Delete, MoveIn, MoveOut ]
dir
(eventHandler config)
putStrLn wd
getLine
removeWatch wd
killINotify n
eventHandler :: TVar Config -> Event -> IO ()
eventHandler conf x@(Modified _ (Just fp)) = handleFilteredFile conf x fp
eventHandler conf x@(MovedIn _ fp _) = handleFilteredFile conf x fp
eventHandler conf x@(MovedOut _ fp _) = handleFilteredFile conf x fp
eventHandler conf x@(Created _ fp) = handleFilteredFile conf x fp
eventHandler conf x@(Deleted _ fp) = handleFilteredFile conf x fp
eventHandler _ _ = return ()
handleFilteredFile conf evt fp =
when (filterHS fp) $ putStrLn evt >> doWork conf
filterHS fp = fileExt fp == "hs"
fileExt = reverse
. takeWhile (/= '.')
. reverse
doWork :: TVar Config -> IO ()
doWork conf = do
config <- readTVarIO conf
if confWorking config
then do
putStrLn "Already working!"
return ()
else do
putStrLn "New work available!"
atomically $ writeTVar conf (config { confWorking = True })
_ <- forkIO $ runCI conf
return ()
runCI :: TVar Config -> IO ()
runCI conf = do
config <- readTVarIO conf
contents <- readFile $ confExecFile config
execContents $ lines contents
atomically $ writeTVar conf (config { confWorking = False })
return ()
execContents :: [String] -> IO Bool
execContents [] = return True
execContents (x:xs) = do
let p = shell x
(_,_,_,h) <- createProcess p
exitCode <- waitForProcess h
case exitCode of
ExitSuccess -> execContents xs
ExitFailure _ -> return False