module System.Nemesis (run, sh, task, desc) where
import Prelude hiding ((.), (>), (^), lookup)
import Control.Monad.State hiding (State, join)
import Data.Default
import Data.Map (Map, insert, empty, lookup, elems)
import System
import GHC.IOBase hiding (liftIO)
import Nemesis.Util
data Task = Task
{
name :: String
, action :: IO ()
, deps :: [String]
, description :: Maybe String
}
data Nemesis = Nemesis
{
tasks :: Map String Task
, target :: String
, current_desc :: Maybe String
}
deriving (Show)
instance Default Nemesis where
def = Nemesis empty def def
instance Default Task where
def = Task def (return ()) def def
instance Show Task where
show x = case x.description of
Nothing -> title
Just s -> title ++ s
where
title = x.name.ljust 20 ' ' ++ ": "
instance Eq Task where
a == b = a.name == b.name
instance Ord Task where
compare = compare_by name
type Unit = StateT Nemesis IO ()
sh :: String -> IO ()
sh s = do
status <- system s
case status of
ExitSuccess -> return ()
ExitFailure code -> error $ s ++ " failed with status code: " ++ show code
run :: Unit -> IO ()
run unit = do
args <- getArgs
if args.null
then help
else execStateT unit def {target = args.first} >>= run_nemesis
where
help = execStateT unit def >>= list_task
list_task n = do
br
n.tasks.elems.mapM_ print
br
br = putStrLn ""
desc :: String -> Unit
desc s = do
n <- get
put n {current_desc = Just s}
task :: String -> IO () -> Unit
task s action =
if s.has ':'
then
let h = s.takeWhile (/= ':')
t = s.dropWhile (/= ':') .tail
in
task' h (t.words)
else
task' s []
where
task' name deps = insert_task def {name, deps, action}
insert_task :: Task -> Unit
insert_task t = do
n <- get
let description = n.current_desc
tasks' = n.tasks.insert (t.name) t {description}
put n {tasks = tasks', current_desc = Nothing}
run_nemesis :: Nemesis -> IO ()
run_nemesis n = run' (n.target)
where
run' :: String -> IO ()
run' s = case (n.tasks.lookup s) of
Nothing -> bye
Just x -> revenge x
where
bye = error $ s ++ " does not exist!"
revenge :: Task -> IO ()
revenge t = t.deps.mapM_ run' >> revenge_and_say
where
revenge_and_say = do
t.action