nemesis 2009.6.12 → 2009.6.13
raw patch · 7 files changed
+166/−79 lines, 7 filesdep +directorydep −mpsPVP ok
version bump matches the API change (PVP)
Dependencies added: directory
Dependencies removed: mps
API changes (from Hackage documentation)
+ System.Nemesis: desc :: String -> Unit
Files
- changelog.md +12/−0
- nemesis.cabal +7/−4
- readme.md +17/−10
- src/Nemesis/Runner.hs +34/−0
- src/Nemesis/Util.hs +65/−0
- src/Runner.hs +0/−44
- src/System/Nemesis.hs +31/−21
changelog.md view
@@ -1,3 +1,15 @@+2009.6.13+---------++### Feature++* add `desc` dsl++### Fix++* super fast compile +* -Wall clean+ 2009.6.12 ---------
nemesis.cabal view
@@ -1,5 +1,5 @@ Name: nemesis-Version: 2009.6.12+Version: 2009.6.13 Build-type: Simple Synopsis: a rake like task management tool Description:@@ -18,13 +18,16 @@ library ghc-options: -Wall- build-depends: base >= 4 && < 5, haskell98, mtl, process, containers, data-default, mps >= 2009.5.13+ build-depends: base >= 4 && < 5, haskell98, mtl, process, containers, data-default hs-source-dirs: src/ exposed-modules: System.Nemesis+ other-modules:+ Nemesis.Util Executable nemesis ghc-options: -Wall- build-depends: base >= 4 && < 5, haskell98, mtl, process, containers, data-default, mps >= 2009.5.13+ build-depends: base >= 4 && < 5, haskell98, mtl, process, containers, data-default, directory hs-source-dirs: src/- main-is: Runner.hs+ main-is: Nemesis/Runner.hs+ other-modules: Nemesis.Util
readme.md view
@@ -9,13 +9,16 @@ in `nem.hs` nemesis = do- task "clean: hello-world" (print "cleaning")+ desc "learn Haskell"+ task "learn-haskell: learn-fp" (putStrLn "Haskell is awesome!") - task "hello-world: ls" $ do- sh "echo HELLO"+ desc "learn Functional Programming"+ task "learn-fp: learn-lisp" $ do+ sh "echo 'into FP'" - task "ls" $ do- sh "ls"+ desc "learn LISP"+ task "learn-lisp" $ do+ sh "echo 'LISP is cool!'" run `nemesis` @@ -25,18 +28,22 @@ run `./nem` - clean: hello-world ls- hello-world: ls- ls:+ learn-fp: learn Functional Programming+ learn-haskell: learn Haskell+ learn-lisp: learn LISP -run `./nem ls`+run `./nem learn-haskell` + LISP is cool!+ into FP+ Haskell is awesome!+ Advance usage ------------- -### Use LANGUAGEW+### Use LANGUAGE Use a separator below language extensions, e.g.
+ src/Nemesis/Runner.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE QuasiQuotes #-}++import Prelude hiding ((.), (>), (^))+import System.Cmd+import Nemesis.Util++start, end :: String+start = "\n\n\n\nmodule Main where\n" ++ "import System.Nemesis"+end = "\n\n\nmain = run nemesis\n"++main :: IO ()+main = do+ dir <- ls "."+ src <- readFile $ dir.filter (belongs_to possible_source) .get_name+ let h = src.lines.takeWhile (lower > starts_with sep > not) .unlines+ t = src.lines.dropWhile (lower > starts_with sep > not) .unlines+ if t.null+ then output $ start ++ h ++ end+ else output $ h ++ start ++ t ++ end+ + system $ "ghc --make -O1 " ++ tmp_name ++ " -o " ++ bin+ system $ "rm " ++ tmp_name+ return ()+ + where+ get_name [] = error "Nemesis does not exists"+ get_name xs = xs.first+ possible_source = ["Nemesis", "nemesis", "nemesis.hs", "Nemesis.hs"]+ sep = "-- nem"+ output = writeFile tmp_name+ tmp_name = "nemesis-tmp.hs"+ bin = "nem"+ +-- helper from mps
+ src/Nemesis/Util.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE NoMonomorphismRestriction #-}++module Nemesis.Util where++import Prelude hiding ((>), (.), (^))+import qualified Data.List as L+import Data.Function (on)+import Control.Arrow ((>>>))+import Data.Char (toLower)+import Data.List (isPrefixOf, (\\))+import System.Directory+import Control.Category (Category)+++-- utility functions from mps++-- base DSL+(.) :: a -> (a -> b) -> b+a . f = f a+infixl 9 .++(^) :: (Functor f) => f a -> (a -> b) -> f b+(^) = flip fmap+infixl 8 ^++(>) :: (Category cat) => cat a b -> cat b c -> cat a c+(>) = (>>>)+infixl 8 >+++join :: [a] -> [[a]] -> [a]+join = L.intercalate++join' :: [[a]] -> [a]+join' = concat++ljust :: Int -> a -> [a] -> [a]+ljust n x xs + | n < xs.length = xs+ | otherwise = ( n.times x ++ xs ).reverse.take n.reverse++compare_by :: (Ord b) => (a -> b) -> a -> a -> Ordering+compare_by = on compare++first :: [a] -> a+first = head++times :: b -> Int -> [b]+times = flip replicate++has :: (Eq a) => a -> [a] -> Bool+has = elem++belongs_to :: (Eq a) => [a] -> a -> Bool+belongs_to = flip elem+++lower :: String -> String+lower = map toLower++starts_with :: String -> String -> Bool+starts_with = isPrefixOf++ls :: String -> IO [String]+ls s = getDirectoryContents s ^ (\\ [".", ".."])
− src/Runner.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE QuasiQuotes #-}--import MPS-import Prelude hiding ((.), (>), (^))-import System.Cmd---start, end :: String-start = [$here|-module Main where-import System.Nemesis---|]--end = [$here|---main = run nemesis-|]--main :: IO ()-main = do- dir <- ls "."- src <- readFile $ dir.filter (belongs_to possible_source) .get_name- let h = src.lines.takeWhile (lower > starts_with sep > not) .unlines- t = src.lines.dropWhile (lower > starts_with sep > not) .unlines- if t.null- then output $ start ++ h ++ end- else output $ h ++ start ++ t ++ end- - system $ "ghc --make " ++ tmp_name ++ " -o " ++ bin- system $ "rm " ++ tmp_name- return ()- - where- get_name [] = error "nem.hs does not exists"- get_name xs = xs.first- possible_source = ["Nem.hs", "nem.hs", "nemesis.hs", "Nemesis.hs"]- sep = "-- nem"- output = writeFile tmp_name- tmp_name = "nemesis-tmp.hs"- bin = "nem"-
src/System/Nemesis.hs view
@@ -1,45 +1,42 @@ {-# LANGUAGE NamedFieldPuns #-} -module System.Nemesis (run, sh, task) where+module System.Nemesis (run, sh, task, desc) where -import MPS hiding (empty)+-- import MPS hiding (empty) import Prelude hiding ((.), (>), (^), lookup) import Control.Monad.State hiding (State, join) import Data.Default import Data.Map (Map, insert, empty, lookup, elems)-import System.Cmd (system) 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 = Nemesis empty def def instance Default Task where- def = Task def (return ()) def+ def = Task def (return ()) def def instance Show Task where- show x - | x.deps.null = title- | otherwise = - [- title- , x.deps.join " "- , ""- ] .concat+ show x = case x.description of+ Nothing -> title+ Just s -> title ++ s where title = x.name.ljust 20 ' ' ++ ": " @@ -57,7 +54,7 @@ status <- system s case status of ExitSuccess -> return ()- ExitFailure code -> error $ s ++ " failed with status code" ++ show code+ ExitFailure code -> error $ s ++ " failed with status code: " ++ show code run :: Unit -> IO () run unit = do@@ -74,19 +71,31 @@ br br = putStrLn "" +desc :: String -> Unit+desc s = do+ n <- get+ put n {current_desc = Just s}+ task :: String -> IO () -> Unit task s action = - let x:xs = s.split "\\s*:\\s*"- in- task' x (xs.join'.words)+ 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 Task {name, deps, action}+ task' name deps = insert_task def {name, deps, action} insert_task :: Task -> Unit insert_task t = do n <- get- let tasks' = n.tasks.insert (t.name) t- put n {tasks = tasks'}+ 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)@@ -99,8 +108,9 @@ bye = error $ s ++ " does not exist!" revenge :: Task -> IO ()- revenge t = t.deps.to_list.mapM_ run' >> revenge_and_say+ revenge t = t.deps.mapM_ run' >> revenge_and_say where revenge_and_say = do -- putStrLn $ "running: " ++ t.name t.action+