packages feed

muon (empty) → 0.1.0.0

raw patch · 20 files changed

+680/−0 lines, 20 filesdep +Globdep +HStringTemplatedep +basesetup-changed

Dependencies added: Glob, HStringTemplate, base, blaze-html, directory, markdown, process, text

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Kaashif Hymabaccus++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 Kaashif Hymabaccus 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.
+ README view
@@ -0,0 +1,47 @@+muon+====+Muon is a static blog generator, meaning that it takes files written in+convenient markup and converts it to HTML and CSS ready to deploy to a web+server.++Installing+----------+First, install the package by getting the darcs repo.++    $ darcs get http://repos.kaashif.co.uk/muon++You can install it using cabal, which you should have installed.++    $ cd muon+    $ cabal install++After that, assuming you have configured cabal and/or your PATH correctly, muon+should be usable. Here are some things you may want to do:++Using Muon+----------+Initialising a blog:++    $ mkdir new-blog+    $ cd new-blog+    $ muon init++Writing a post:++    $ vi posts/new.post++Regenerating the site, creating a tree of files in the ./site directory.++    $ muon generate++Notes+-----+When writing posts, make sure you put the title on the first line, the date on+the second, and a short description (for the archive) on the third line. The+rest should be valid Markdown. See the posts/ directory after site+initialisation for some examples.++The posts are ordered lexicographically, _not_ by date. This means "aaa.post"+will always come before "bbb.post", regardless of the date contained in the file.++"muon upload" is currently hardcoded. Stay tuned for per-blog config files.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ muon.cabal view
@@ -0,0 +1,32 @@+-- Initial muon.cabal generated by cabal init.  For further documentation, +-- see http://haskell.org/cabal/users-guide/++name:                muon+version:             0.1.0.0+synopsis:            Static blog generator+description:         Static blog generator+homepage:            http://repos.kaashif.co.uk/darcs?r=muon;a=summary+license:             BSD3+license-file:        LICENSE+author:              Kaashif Hymabaccus+maintainer:          kaashifhymabaccus@gmail.com+copyright:           Copyright (c) 2014 Kaashif Hymabaccus+category:            Web+build-type:          Simple+cabal-version:       >=1.8+data-dir:            src+data-files:          def/style/style.css+                     def/templates/*.st+                     def/posts/*.post+                     def/pages/about+                     def/pages/contact+extra-source-files:  src/*.hs README++source-repository head+    type: darcs+    location: http://repos.kaashif.co.uk/muon++executable muon+  main-is:             Main.hs+  build-depends:       base ==4.6.*, text ==0.11.*, HStringTemplate ==0.7.*, directory ==1.2.*, Glob ==0.7.*, process ==1.2.*, blaze-html ==0.7.*, markdown ==0.1.*+  hs-source-dirs:      src
+ src/Archive.hs view
@@ -0,0 +1,45 @@+module Archive where++import System.Directory+import qualified Data.Text as T+import Site+import Text.StringTemplate+import Post++sitePath = "site/"+mkdir = createDirectoryIfMissing False++archiveTemplate = do+    templates <- directoryGroup "templates" :: IO (STGroup T.Text)+    let Just t = getStringTemplate "generic" templates+    return t++makeTableRow ::  Post -> String+makeTableRow p = "<tr>"+              ++ "<td><a href=" ++ T.unpack (link p) ++ ">" ++ T.unpack (title p) ++ "</a></td>"+              ++ "<td>" ++ T.unpack (date p) ++ "</td>"+              ++ "<td>" ++ T.unpack (comment p) ++ "</td>"+              ++ "</tr>"++makeTable ::  [Post] -> T.Text+makeTable ps = T.pack+             $ "<table>"+            ++ "<tr><td>Title</td><td>Date</td><td>Comment</td></tr>"+            ++ unlines (map makeTableRow ps)+            ++ "</table>"++renderGenericArchive t c = render+                         $ setAttribute "site" defaultSite+                         $ setAttribute "content" c t++renderArchive = do+    ps <- getAllPosts+    t <- archiveTemplate+    return $ renderGenericArchive t (makeTable $ reverse ps)++writeArchive ::  T.Text -> IO ()+writeArchive s = do+    mkdir $ sitePath ++ "archive/"+    writeFile (sitePath ++ "archive/index.html") (T.unpack s)++generateArchive = renderArchive >>= writeArchive >> putStrLn "Generated archive"
+ src/Constant.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE OverloadedStrings #-}+module Constant where++import System.Directory++sitePath = "site/"+pageNames = ["about", "contact"]+siteDirs = ["site", "style", "posts", "templates", "pages"]+mkdir = createDirectoryIfMissing False
+ src/Home.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+module Home where++import Post+import Text.StringTemplate+import System.Directory+import Site+import qualified Data.Text as T++sitePath = "site/"+mkdir = createDirectoryIfMissing False++homeTemplate = do+    templates <- directoryGroup "templates" :: IO (STGroup T.Text)+    let Just t = getStringTemplate "generic" templates+    return t++renderGenericHome ::  StringTemplate T.Text -> [T.Text] -> T.Text+renderGenericHome t cs = render+                       $ setAttribute "site" defaultSite+                       $ setAttribute "content" (T.unlines cs) t++renderHome ::  IO T.Text+renderHome = do+    cs <- getAllExtracts+    t <- homeTemplate+    return $ renderGenericHome t $ reverse cs++writeHome ::  T.Text -> IO ()+writeHome s = do+    mkdir $ sitePath ++ "home/"+    writeFile (sitePath ++ "home/index.html") (T.unpack s)+    writeFile (sitePath ++ "index.html") (T.unpack s)++generateHome = renderHome >>= writeHome >> putStrLn "Generated home"
+ src/Main.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE OverloadedStrings #-}+module Main where++import qualified Data.Text as T+import Text.StringTemplate+import Control.Monad+import System.Directory+import System.FilePath.Glob+import System.Environment+import System.Process (runCommand)+import Post (generatePosts)+import Home (generateHome)+import Archive (generateArchive)+import Site (defaultSite)+import Page (generatePages)+import Constant+import Paths_muon++ensureDirs = mkdir sitePath++createDefaults = do+    d <- getDataFileName "def"+    mapM_ mkdir siteDirs+    mkdir "static"+    copyFile (d ++ "/style/style.css") "style/style.css"+    copyFile (d ++ "/posts/first.post") "posts/first.post"+    copyFile (d ++ "/posts/second.post") "posts/second.post"+    copyFile (d ++ "/templates/post.st") "templates/post.st"+    copyFile (d ++ "/templates/header.st") "templates/header.st"+    copyFile (d ++ "/templates/footer.st") "templates/footer.st"+    copyFile (d ++ "/templates/generic.st") "templates/generic.st"+    copyFile (d ++ "/pages/about") "pages/about"+    copyFile (d ++ "/pages/contact") "pages/contact"+    putStrLn "Initialised site directory"++copyStatic = do+    copyFile "style/style.css" (sitePath ++ "style.css")+    runCommand $ "cp -R static " ++ sitePath ++ "static"++generateSite = copyStatic+            >> generatePosts+            >> generateHome+            >> generateArchive+            >> generatePages++showHelp = putStrLn "Usage: muon [commands]\n\n\+\  help        show this help message\n\+\  init        initialise a default blog in the current dir\n\+\  generate    generate static blog in 'site' directory\n\n\+\Report bugs to <kaashif@kaashif.co.uk>"++clearSite = mkdir sitePath +         >> removeDirectoryRecursive sitePath +         >> mkdir sitePath++rsyncCmd = "rsync -a --delete site/ root@webserver:/var/www/htdocs/"++proc ::  String -> IO ()+proc cmd+    | cmd == "init" = createDefaults+    | cmd == "generate" = clearSite >> generateSite+    | cmd == "upload" = void $ runCommand rsyncCmd+    | otherwise = showHelp++getArgsHelp = do+    a <- getArgs+    if length a < 1+        then return ["help"]+        else return a++takeAction = getArgsHelp >>= mapM_ proc++main = ensureDirs >> takeAction
+ src/Page.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Page where++import qualified Data.Text as T+import Site+import Text.StringTemplate+import Text.StringTemplate.GenericStandard+import Constant++pageTemplate = do+    templates <- directoryGroup "templates" :: IO (STGroup T.Text)+    let Just t = getStringTemplate "generic" templates+    return t++renderPage ::  StringTemplate T.Text -> T.Text -> T.Text+renderPage t c = render+               $ setAttribute "site" defaultSite+               $ setAttribute "content" c t++renderPageFile ::  String -> IO T.Text+renderPageFile p = do+    c <- readFile $ "pages/" ++ p+    t <- pageTemplate+    return $ renderPage t (T.pack c)++writePage ::  String -> T.Text -> IO ()+writePage p c = do+    mkdir $ sitePath ++ p+    writeFile (sitePath ++ p ++ "/index.html") (T.unpack c)++generatePage p = do+    c <- renderPageFile p+    writePage p c+    putStrLn $ "Generated " ++ p++generatePages = mapM_ generatePage pageNames
+ src/Post.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Post where++import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import Text.StringTemplate+import Text.StringTemplate.GenericStandard+import Text.Blaze.Html.Renderer.Text+import Text.Markdown+import System.Directory+import System.FilePath.Glob+import Data.Typeable+import Data.Data+import Data.List+import Site+import Control.Monad+import Constant++postPath = "posts/" :: String++data Post = Post { title :: T.Text+                 , link :: T.Text+                 , date :: T.Text+                 , comment :: T.Text+                 , content :: T.Text+                 } deriving (Data, Typeable, Show)++postTemplate = do+    templates <- directoryGroup "templates" :: IO (STGroup T.Text)+    let Just t = getStringTemplate "post" templates+    return t++renderPost ::  StringTemplate T.Text -> Post -> T.Text+renderPost t p = render+               $ setAttribute "site" defaultSite+               $ setAttribute "post" p t++renderName ::  StringTemplate T.Text -> String -> IO T.Text+renderName t n = liftM (renderPost t) (getPost (0, n))++makeExtract ::  Post -> T.Text+makeExtract p = T.pack+                  $ "<h2>" ++ T.unpack (title p) ++ "</h2>"+                 ++ "<h3>" ++ T.unpack (date p) ++ "</h3>"+                 ++  unlines (take 25 $ lines $ T.unpack $ content p)+                 ++ "<br/><br/><a href=\'" ++ T.unpack (link p) ++ "\'>Read more...</a>"+                 ++ "</code></pre></li></ul></ol><hr/>"++makePost ::  (Int, [String]) -> Post+makePost l = Post { title  = T.pack $ head (snd l)+                  , link = T.pack $ "/post/" ++ show (fst l)+                  , date = T.pack $ snd l !! 1+                  , comment = T.pack $ snd l !! 2+                  , content = T.pack $ extractContent (snd l) }++extractContent ::  [String] -> String+extractContent l = TL.unpack+                 $ renderHtml+                 $ markdown def+                 $ TL.pack+                 $ unlines+                 $ drop 3 l++getPost ::  (Int, FilePath) -> IO Post+getPost n = do+    c <- readFile (snd n)+    return $ makePost (fst n, lines c)++getNames ::  IO [(Int, FilePath)]+getNames = do+    d <- globDir [compile "*.post"] postPath+    let l = (sort . head . fst) d+    return $ zip [1..(length l)] l++renderPosts ::  IO [T.Text]+renderPosts = do+    templates <- directoryGroup "templates" :: IO (STGroup T.Text)+    let Just t = getStringTemplate "post" templates+    ns <- getNames+    mapM (renderName t . snd) ns++writePosts ::  [T.Text] -> IO ()+writePosts ps = mapM_ writePost (zip [1..(length ps)] ps)++writePost ::  (Int, T.Text) -> IO ()+writePost p = do+    mkdir $ sitePath ++ "post"+    mkdir $ sitePath ++ "post/" ++ show (fst p)+    writeFile (sitePath ++ "post/" ++ show (fst p) ++ "/index.html") (T.unpack $ T.append "\n" $ snd p)++getAllPosts = do+    ns <- getNames+    mapM getPost ns++getAllExtracts = do+    ps <- getAllPosts+    return $ map makeExtract ps++generatePosts = renderPosts >>= writePosts >> putStrLn "Generated posts"
+ src/Site.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Site (defaultSite) where++import qualified Data.Text as T+import Data.Typeable+import Data.Data++data Site = Site { title :: T.Text+                 , style :: T.Text+                 , author :: T.Text+                 , tagline :: T.Text+                 } deriving (Data, Typeable, Show)++defaultSite = Site { title = "Default Blog"+                   , style = "/style.css"+                   , author = "Your Name"+                   , tagline = "Description of this blog"+                   }
+ src/def/pages/about view
@@ -0,0 +1,1 @@+<p>This is about you.</p>
+ src/def/pages/contact view
@@ -0,0 +1,1 @@+<p>Contact you at your email</p>
+ src/def/posts/first.post view
@@ -0,0 +1,5 @@+First Post+2014-04-05+A comment++Some content
+ src/def/posts/second.post view
@@ -0,0 +1,5 @@+Second Post+2014-04-06+Another comment++Some more content.
+ src/def/style/style.css view
@@ -0,0 +1,195 @@+html {+	background: #FFFFFF;+}++body {+	padding: 50px 0;+	margin: 0;+	font-family: Helvetica;+	color: #555;+	font-weight: 300;+}++.wrapper {+	max-width: 640px;+	margin: 0 auto;+	background: #FFFFFF;+	border-radius: 8px;+}++header, section, footer {+	display: block;+}++a {+	color: #2D2E2F;+	text-decoration: none;+}++p {+	margin: 0 0 20px;+	padding: 0;+}++strong {+	color: #222;+	font-weight: 700;+}++header {+	border-radius: 8px 8px 0 0;+	background: #FFFFFF;+	position: relative;+	padding: 20px 20px 30px 20px;+	margin-top: -1px;+}++header h1 {+	margin: 0;+	padding: 0;+	font-size: 24px;+	line-height: 1.2;+	color: #2D2E2F;+}+header p {+	margin: 0;+	color: #2D2E2F;+	font-size: 15px;+}+header ul {+	float: left;+	list-style: none;+	margin-left: -45px;+}+header ul li {+	float: left;+	padding: 13px 5px;+}+main {+	font-size: 15px;+	border-top: 1px solid #fff;+	position: relative;+	border-radius: 8px;+}++.content {+	padding: 15px 20px 20px 20px;+}++h1, h2, h3, h4, h5, h6 {+	color: #666;+	padding: 0;+	margin: 0 0 20px;+	line-height: 1.2;+}++p, ul, ol, table, pre, dl {+	margin: 0 0 20px;+}++h1, h2, h3 {+	line-height: 1.1;+}++h1 {+	font-size: 28px;+	color: #2D2E2F;+}++h2 {+	color: #2D2E2F;+}++h3, h4, h5, h6 {+	color: #494949;+}++blockquote {+	margin: 0 -20px 20px;+	padding: 15px 20px 1px 40px;+	font-style: italic;+	background: #ccc;+	background: rgba(0, 0, 0, 0.06);+	color: #222;+}++img {+	max-width:100%;+	display: block;+	margin-left: auto;+	margin-right: auto;+}++code, pre {+	color: #333;+	font-size: 12px;+}++pre {+	padding: 20px;+	background: #DDDDDD;+	color: #333333;+	margin: 0 -20px 20px;+	overflow-x:auto;+}+li pre {+	margin-left: -60px;+	padding-left: 60px;+}++table {+	width: 100%;+	border-collapse: collapse;+}++th, td {+	text-align: left;+	padding: 5px 10px;+	border-bottom: 1px solid #aaa;+}++dt {+	color: #222;+	font-weight: 700;+}++th {+	color: #222;+}++small {+	font-size: 11px;+}++hr {+	border: 0;+	background: #aaa;+	height: 0px;+	margin: 0 0 20px;+}++hr#header {+	clear: both;+	visibility: hidden;+}++footer {+	width: 640px;+	margin: 0 auto;+	padding: 20px 0 0;+	color: #aaa;+	overflow: hidden;+}+footer a {+	color: #bbb;+	font-weight: bold;+}+footer p {+	float: left;+}+footer p + p {+	float: right;+}+.latex {+	text-align: center;+}
+ src/def/templates/footer.st view
@@ -0,0 +1,10 @@+</div>+</main>+</div>+<footer>+<p>+&copy; <time>2014</time> $site.author$<br/>+</p>+</footer>+</body>+</html>
+ src/def/templates/generic.st view
@@ -0,0 +1,3 @@+$header()$+$content$+$footer()$
+ src/def/templates/header.st view
@@ -0,0 +1,26 @@+<!DOCTYPE html>+<html>+<head>+<title>$site.title$</title>+<link rel="stylesheet" type="text/css" href="$site.style$">+</head>+<body>+<div class="wrapper">+<main>+<header>+        <h1>$site.title$</h1>+        <p>$site.tagline$</p>+        <ul>+            <li> <a href="/home">Home</a></li>+            <li>//</li>+            <li> <a href="/about">About</a></li>+            <li>//</li>+            <li> <a href="/contact">Contact</a></li>+            <li>//</li>+            <li> <a href="/archive">Archive</a></li>+            <li>//</li>+            <li> <a href="http://git.kaashif.co.uk/">Code</a></li>+        </ul>+</header>+<hr id="header" />+<div class="content">
+ src/def/templates/post.st view
@@ -0,0 +1,5 @@+$header()$+<h1>$post.title$</h1>+<h2>$post.date$</h2>+$post.content$+$footer()$