-
Notifications
You must be signed in to change notification settings - Fork 26
/
Main.hs
147 lines (106 loc) · 3.93 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Maybe
import Control.Applicative
import Control.Concurrent
import Control.Exception (throwIO, SomeException)
import Control.Monad
import Control.Monad.CatchIO
import Control.Monad.Reader.Class
import Control.Monad.Trans
import Data.Typeable
import Snap.Http.Server
import Snap.Types
import Snap.Util.FileServe
import Snap.Util.GZip
import System
import System.Directory
import System.Exit
import System.Process
import Text.Templating.Heist
import Text.XML.Expat.Tree
renderTmpl :: MVar (TemplateState Snap)
-> ByteString
-> Snap ()
renderTmpl tsMVar n = do
ts <- liftIO $ readMVar tsMVar
maybe pass writeBS =<< renderTemplate ts n
templateServe :: MVar (TemplateState Snap)
-> Snap ()
templateServe tsMVar =
ifTop (renderTmpl tsMVar "index") <|>
path "admin/reload" (reloadTemplates tsMVar) <|>
(renderTmpl tsMVar . B.pack =<< getSafePath)
reloadTemplates :: MVar (TemplateState Snap)
-> Snap ()
reloadTemplates tsMVar = do
liftIO $ modifyMVar_ tsMVar $ const $
liftM bindMarkdownTag $ loadTemplates "templates"
site :: MVar (TemplateState Snap) -> Snap ()
site tsMVar = withCompression $ h1 <|> h2 tsMVar
h1 :: Snap ()
h1 = fileServe "static"
h2 :: MVar (TemplateState Snap) -> Snap ()
h2 m = templateServe m
bindMarkdownTag :: TemplateState Snap -> TemplateState Snap
bindMarkdownTag = bindSplice "markdown" markdownSplice
data PandocMissingException = PandocMissingException
deriving (Typeable)
instance Show PandocMissingException where
show PandocMissingException =
"Cannot find the \"pandoc\" executable; is it on your $PATH?"
instance Exception PandocMissingException
data MarkdownException = MarkdownException String
deriving (Typeable)
instance Show MarkdownException where
show (MarkdownException e) =
"Markdown error: pandoc replied:\n\n" ++ e
instance Exception MarkdownException
pandoc :: FilePath -> ByteString -> IO ByteString
pandoc pandocPath s = do
-- using the crummy string functions for convenience here
let s' = B.unpack s
(ex, sout, serr) <- readProcessWithExitCode pandocPath args s'
when (isFail ex) $ throw $ MarkdownException serr
return $ B.pack sout
where
isFail ExitSuccess = False
isFail _ = True
args = [ "-S", "--no-wrap" ]
markdownSplice :: Splice Snap
markdownSplice = do
pdMD <- liftIO $ findExecutable "pandoc"
liftIO $ B.putStrLn $ B.concat ["pandoc?", B.pack (show pdMD)]
when (isNothing pdMD) $ liftIO $ throwIO PandocMissingException
tree <- ask
let txt = textContent tree
liftIO $ B.putStrLn "got text"
liftIO $ B.putStrLn txt
markup <- liftIO $ pandoc (fromJust pdMD) txt
liftIO $ B.putStrLn "got markup"
liftIO $ B.putStrLn markup
let ee = parse' heistExpatOptions markup
case ee of
(Left e) -> liftIO $ throw $ MarkdownException $
"Error parsing markdown output: " ++ show e
(Right n) -> return [n]
-- FIXME: remove
killMe :: ThreadId -> Snap ()
killMe t = liftIO (exitSuccess >> killThread t)
main :: IO ()
main = do
args <- getArgs
port <- case args of
[] -> error "You must specify a port!" >> exitFailure
port:_ -> return $ read port
ts <- loadTemplates "templates"
tsMVar <- newMVar $ bindMarkdownTag ts
(try $ httpServe "*" port "achilles"
(Just "access.log")
(Just "error.log")
(site tsMVar)) :: IO (Either SomeException ())
putStrLn "exiting"
return ()