nemesis 2009.6.13 → 2009.6.13.1
raw patch · 12 files changed
+235/−148 lines, 12 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- System.Nemesis: desc :: String -> Unit
- System.Nemesis: sh :: String -> IO ()
- System.Nemesis: task :: String -> IO () -> Unit
+ System.Nemesis: Nemesis :: Map String Task -> String -> Maybe String -> Nemesis
+ System.Nemesis: Task :: String -> IO () -> [String] -> Maybe String -> Task
+ System.Nemesis: action :: Task -> IO ()
+ System.Nemesis: current_desc :: Nemesis -> Maybe String
+ System.Nemesis: data Nemesis
+ System.Nemesis: data Task
+ System.Nemesis: deps :: Task -> [String]
+ System.Nemesis: description :: Task -> Maybe String
+ System.Nemesis: insert_task :: Task -> Unit
+ System.Nemesis: name :: Task -> String
+ System.Nemesis: run_nemesis :: Nemesis -> IO ()
+ System.Nemesis: target :: Nemesis -> String
+ System.Nemesis: tasks :: Nemesis -> Map String Task
+ System.Nemesis: type Unit = StateT Nemesis IO ()
+ System.Nemesis.DSL: clean :: [String] -> Unit
+ System.Nemesis.DSL: desc :: String -> Unit
+ System.Nemesis.DSL: sh :: String -> IO ()
+ System.Nemesis.DSL: task :: String -> IO () -> Unit
Files
- LICENSE +1/−1
- Nemesis.hs +33/−0
- changelog.md +13/−1
- knownissue.md +1/−0
- nemesis.cabal +6/−5
- readme.md +35/−12
- src/Nemesis/Runner.hs +0/−34
- src/Nemesis/Util.hs +0/−65
- src/System/Nemesis.hs +2/−30
- src/System/Nemesis/DSL.hs +41/−0
- src/System/Nemesis/Runner.hs +39/−0
- src/System/Nemesis/Util.hs +64/−0
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) <YEAR>, <OWNER>+Copyright (c) 2009, Jinjing Wang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ Nemesis.hs view
@@ -0,0 +1,33 @@+-- template nemesis file++import System.Nemesis.DSL (clean)++nemesis = do+ + clean+ [ "**/*.hi"+ , "**/*.o"+ , "manifest"+ ]+ + desc "learn Haskell"+ task "learn-haskell: learn-fp" (putStrLn "Haskell is awesome!")+ + desc "learn Functional Programming"+ task "learn-fp : learn-lisp" $ do+ sh "echo 'into FP'"++ desc "learn LISP"+ task "learn-lisp" $ do+ sh "echo 'LISP is cool!'"+ + task "dist" $ do+ sh "cabal clean"+ sh "cabal configure"+ sh "cabal sdist"++ task "i" (sh "ghci -isrc src/System/Nemesis.hs")++ task "manifest" $ do+ sh "find . | grep 'hs$' > manifest"+
changelog.md view
@@ -1,9 +1,21 @@+2009.6.13.1+-----------++### Feature++* add `clean` keyword++### Fix++* allow space before ":" in task description+* remove `.o .hi` for temp file+ 2009.6.13 --------- ### Feature -* add `desc` dsl+* add `desc` keyword ### Fix
+ knownissue.md view
@@ -0,0 +1,1 @@+* does not detect cycles
nemesis.cabal view
@@ -1,5 +1,5 @@ Name: nemesis-Version: 2009.6.13+Version: 2009.6.13.1 Build-type: Simple Synopsis: a rake like task management tool Description:@@ -14,7 +14,7 @@ Cabal-version: >= 1.2 category: Web homepage: http://github.com/nfjinjing/nemesis-data-files: readme.md, changelog.md+data-files: readme.md, changelog.md, knownissue.md, Nemesis.hs library ghc-options: -Wall@@ -22,12 +22,13 @@ hs-source-dirs: src/ exposed-modules: System.Nemesis+ System.Nemesis.DSL other-modules:- Nemesis.Util+ System.Nemesis.Util Executable nemesis ghc-options: -Wall build-depends: base >= 4 && < 5, haskell98, mtl, process, containers, data-default, directory hs-source-dirs: src/- main-is: Nemesis/Runner.hs- other-modules: Nemesis.Util+ main-is: System/Nemesis/Runner.hs+ other-modules: System.Nemesis.Util
readme.md view
@@ -1,15 +1,46 @@ Nemesis: a rake like task management tool for haskell ===================================================== +Demo+----+ + import System.Nemesis.DSL (clean)+ + nemesis = do++ clean+ [ "**/*.hi"+ , "**/*.o"+ , "manifest"+ ]+ + task "dist" $ do+ sh "cabal clean"+ sh "cabal configure"+ sh "cabal sdist"++ task "i" (sh "ghci -isrc src/System/Nemesis.hs")++ task "manifest" $ do+ sh "find . | grep 'hs$' > manifest"+ Tutorial -------- +### Install++ cabal update; cabal install nemesis+ ### DSL -in `nem.hs`+Put the following code into a file named `Nemesis` nemesis = do+ + -- desc is optional, it gives some description to the following task desc "learn Haskell"+ + -- syntax: task "keyword: dependencies" io-action task "learn-haskell: learn-fp" (putStrLn "Haskell is awesome!") desc "learn Functional Programming"@@ -52,17 +83,8 @@ -- Nem nemesis = do-- task "dist" $ do- sh "cabal clean"- sh "cabal configure"- sh "cabal sdist"- task "i" (sh "ghci -isrc src/System/Nemesis.hs") - task "manifest" $ do- sh "find . | grep 'hs$' > manifest"- currently the separator `-- Nem` is hard coded ### Build it yourself@@ -71,11 +93,12 @@ module Main where - import System.Nemesis+ import System.Nemesis (run)+ import System.Nemesis.DSL (desc, task, sh) nemesis = do task "i" (sh "ghci -isrc src/System/Nemesis.hs") - main = nemesis+ main = run nemesis
− src/Nemesis/Runner.hs
@@ -1,34 +0,0 @@-{-# 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
@@ -1,65 +0,0 @@-{-# 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/System/Nemesis.hs view
@@ -1,15 +1,13 @@ {-# LANGUAGE NamedFieldPuns #-} -module System.Nemesis (run, sh, task, desc) where+module System.Nemesis where --- 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-import GHC.IOBase hiding (liftIO)-import Nemesis.Util+import System.Nemesis.Util data Task = Task {@@ -48,13 +46,6 @@ type Unit = StateT Nemesis IO () --- sh :: String -> IO GHC.IOBase.ExitCode-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@@ -71,24 +62,6 @@ 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@@ -113,4 +86,3 @@ revenge_and_say = do -- putStrLn $ "running: " ++ t.name t.action-
+ src/System/Nemesis/DSL.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE NamedFieldPuns #-}++module System.Nemesis.DSL where++import Control.Monad.State hiding (State, join)+import Data.Default+import Prelude hiding ((.), (>), (^), lookup)+import System+import System.Nemesis+import System.Nemesis.Util++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.strip) (t.words)+ else+ task' s []+ where+ task' name deps = insert_task def {name, deps, action}+ strip = dropWhile (== ' ') > reverse > dropWhile (== ' ') > reverse++sh :: String -> IO ()+sh s = do+ status <- system s+ case status of + ExitSuccess -> return ()+ ExitFailure code -> error $ s ++ " failed with status code: " ++ show code++clean :: [String] -> Unit+clean xs = do+ desc "Remove any temporary products. map (rm -rf)"+ task "clean" $ mapM_ (\x -> sh ("rm -rf " ++ x)) xs
+ src/System/Nemesis/Runner.hs view
@@ -0,0 +1,39 @@+import Prelude hiding ((.), (>), (^))+import System.Cmd+import System.Nemesis.Util++start, end, sep_block :: String+sep_block = "\n\n\n\n"+start = sep_block ++ start_nemesis ++ start_nemesis_dsl+ where + start_nemesis = "import System.Nemesis (run)\n"+ start_nemesis_dsl = "import System.Nemesis.DSL (sh, task, desc)\n"+end = sep_block ++ "main = 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+ system $ "rm " ++ tmp_o+ system $ "rm " ++ tmp_hi+ 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"+ tmp_o = "nemesis-tmp.o"+ tmp_hi = "nemesis-tmp.hi"+ bin = "nem"+
+ src/System/Nemesis/Util.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE NoMonomorphismRestriction #-}++module System.Nemesis.Util where++import Control.Arrow ((>>>))+import Control.Category (Category)+import Data.Char (toLower)+import Data.Function (on)+import Data.List (isPrefixOf, (\\))+import Prelude hiding ((>), (.), (^))+import System.Directory+import qualified Data.List as L++-- 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 ^ (\\ [".", ".."])