nemesis-titan (empty) → 2013.6.13
raw patch · 8 files changed
+340/−0 lines, 8 filesdep +HStringTemplatedep +airdep +basesetup-changed
Dependencies added: HStringTemplate, air, base, bytestring, directory, filepath, hspec, nemesis, random, uuid
Files
- LICENSE +31/−0
- Nemesis +25/−0
- Setup.lhs +4/−0
- changelog.md +0/−0
- known-issues.md +0/−0
- nemesis-titan.cabal +23/−0
- readme.md +50/−0
- src/System/Nemesis/Titan.hs +207/−0
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2013, 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:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Jinjing Wang nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Nemesis view
@@ -0,0 +1,25 @@+import System.Nemesis.Env+import Air.Env ((-))+import Prelude hiding ((-))+import System.Nemesis.Titan+import System.Nemesis.Jinjing++main = run nemesis++nemesis = do+ + clean+ [ "**/*.hi"+ , "**/*.o"+ , "manifest"+ , "main"+ , "nemesis-tmp.*"+ , "config/Test"+ , "src/Test.hs"+ ]+ + cabal_dist++ console ["-isrc", "-Wall"] "src/System/Nemesis/Titan"++ titan "Main.hs"
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ changelog.md view
+ known-issues.md view
+ nemesis-titan.cabal view
@@ -0,0 +1,23 @@+Name: nemesis-titan+Version: 2013.6.13+Build-type: Simple+Synopsis: A collection of Nemesis tasks to bootstrap a Haskell project with a focus on continuous integration+Description: ++License: BSD3+License-file: LICENSE+Author: Jinjing Wang+Maintainer: Jinjing Wang <nfjinjing@gmail.com>+Build-Depends: base+Cabal-version: >= 1.2+category: Web+homepage: http://github.com/nfjinjing/nemesis-titan+data-files: readme.md, changelog.md, known-issues.md, Nemesis++library+ ghc-options: -Wall+ build-depends: base >= 4 && < 100, nemesis, air >= 2011.6.19, uuid, random, directory, bytestring, filepath, HStringTemplate, hspec+ + hs-source-dirs: src/+ exposed-modules: + System.Nemesis.Titan
+ readme.md view
@@ -0,0 +1,50 @@+Requirements+============++* [Guard](https://github.com/guard/guard)+* [Angel](https://github.com/MichaelXavier/Angel)++Install+=======+ + cabal install nemesis-titan+ cabal install air-extra++Usage+=====++ mkdir my_project+ cd my_project+++Bootstrap+---------++ curl https://raw.github.com/nfjinjing/nemesis-titan/master/vendor/Nemesis -o Nemesis+ ++List available tasks+--------------------++ runghc Nemesis+ ++Generate "Main.hs"+-------------------++ runghc Nemesis Main/init+++Start the continuous integration process+------------------------------------------++ runghc Nemesis Main/titan+++Check+=====++Make some changes in `src/Main.hs` and see your code gets auto compiled and tested in the console.+ ++
+ src/System/Nemesis/Titan.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE QuasiQuotes #-}++module System.Nemesis.Titan where+ +import System.Nemesis.Env+import System.Nemesis (Unit)++import Air.Env+import Prelude ()+import qualified Data.ByteString.Char8 as B+import qualified Data.UUID as UUID+import System.Directory+import System.Random++import System.Environment (getArgs)+import System.FilePath++import Air.TH (here)++import Test.Hspec+import Text.StringTemplate++angel_template :: StringTemplate String+angel_template = newSTMP - [here|+server {+ exec = "runghc Nemesis $label$/run"+ stdout = "/dev/stdout"+ stderr = "/dev/stderr"+ delay = 0+}++code-reload {+ exec = "runghc Nemesis $label$/guard"+ stdout = "/dev/stdout"+ stderr = "/dev/stderr"+ delay = 0+}++|]+++guard_template :: StringTemplate String+guard_template = newSTMP - [here|+guard :shell do+ watch(%r{^src/.+hs\$}) do |m|+ puts "Changed #{m[0]}"+ `runghc Nemesis $label$/compile && runghc Nemesis $label$/kill`+ end+end++|]+++haskell_template :: StringTemplate String+haskell_template = newSTMP - [here|+module Main where++import Air.Extra (with_spec, halt)+import System.Nemesis.Jinjing.Angel+import Test.Hspec++spec :: IO ()+spec = hspec \$ do+ describe "$label$" \$ do+ it "should run spec" True++main = do+ with_spec spec halt++|]++titan_spec :: IO ()+titan_spec = hspec - do+ describe "Titan" - do+ it "should run spec" True+ + it "should use templates" - do+ let text = render - setAttribute "label" "Main" angel_template+ + -- puts text+ + text `shouldSatisfy` (null > not)+ ++get_label_file_name :: IO (Maybe (String, String))+get_label_file_name = do+ xs <- io getArgs++ case xs of+ (_:file_name:[]) -> + let label = file_name.takeBaseName+ in+ return - Just (label, file_name)+ + (_:label:file_name:[]) ->+ return - Just (label, file_name)+ + _ -> return Nothing+ + ++titan :: String -> Unit+titan file_name = do+ let label = file_name.takeBaseName+ titan_with_label_file_name label file_name++titan_with_label_file_name :: String -> String -> Unit+titan_with_label_file_name label file_name = titan_with_label_file_name_custom_task label file_name (return ())+++titan_with_label_file_name_custom_task :: String -> String -> Unit -> Unit+titan_with_label_file_name_custom_task label file_name custom_tasks = do+ namespace label - do+ + let + pid_name = "uuid.txt"+ bin_directory = ".bin"+ config_name = "config"+ config_directory = config_name / label+ angel_path = config_directory / "Angel.conf"+ guard_path = config_directory / "Guardfile"+ + pid_directory = bin_directory / label+ pid_path = pid_directory / pid_name++ desc "Initialize a Titan node"+ task "init" - io - do+ let+ haskell_source_directory = "src"+ haskell_path = haskell_source_directory / file_name+ ++ createDirectoryIfMissing True config_directory+ createDirectoryIfMissing True haskell_source_directory+ + let + angel_file_content = render - setAttribute "label" label angel_template+ guard_file_content = render - setAttribute "label" label guard_template+ haskell_file_content = render - setAttribute "label" label haskell_template+ + let {+ write_if_not_exist file_path str = do+ file_exist <- doesFileExist file_path+ if not - file_exist+ then+ B.writeFile file_path - B.pack str+ else do+ puts - file_path + " already exists!"+ return ()+ }+ write_if_not_exist angel_path angel_file_content + write_if_not_exist guard_path guard_file_content + write_if_not_exist haskell_path haskell_file_content+ + + let { get_and_create_if_missing_upid = do+ createDirectoryIfMissing True pid_directory++ pid_exist <- doesFileExist pid_path+++ if pid_exist+ then do+ uuid <- B.readFile pid_path ^ B.unpack+ puts - "UPID: " + uuid+ return uuid + else do+ uuid <- randomIO ^ UUID.toString+ puts - "Created UPID: " + uuid+ B.writeFile pid_path - uuid.B.pack+ return - uuid+ }+ + let { get_bin = do+ uuid <- get_and_create_if_missing_upid+ return - pid_directory / uuid+ }++ desc "Start the Titan managed process"+ task "titan:uuid compile" - do+ sh - "angel " + angel_path++ + desc "Create a uuid for this process if not already exist"+ task "uuid" - do+ io - void - get_and_create_if_missing_upid++ desc "Compile the binary"+ task "compile" - do+ bin <- get_bin+ sh - "ghc --make -isrc -threaded src/" + file_name + " -o " + bin++ desc "Start the process"+ task "run" - do+ bin <- get_bin+ sh - bin++ desc "Kill the process"+ task "kill" - do+ upid <- get_and_create_if_missing_upid+ sh - "killall " + upid + "; true"+ + desc "Start the Guard proceses"+ task "guard" - do+ sh - "guard --no-bundler-warning -G " + guard_path+ + custom_tasks