on master help sign in
Add Unix filters as compilers
12a0e53Jasper Van der Jeugt
src/Hakyll.hs+2
@@ -8,6 +8,7 @@ module Hakyll
8 , module Hakyll.Core.Identifier.Pattern
8 , module Hakyll.Core.Identifier.Pattern
9 , module Hakyll.Core.Routes
9 , module Hakyll.Core.Routes
10 , module Hakyll.Core.Rules
10 , module Hakyll.Core.Rules
11+ , module Hakyll.Core.UnixFilter
11 , module Hakyll.Core.Util.Arrow
12 , module Hakyll.Core.Util.Arrow
12 , module Hakyll.Core.Util.File
13 , module Hakyll.Core.Util.File
13 , module Hakyll.Core.Writable
14 , module Hakyll.Core.Writable
@@ -32,6 +33,7 @@ import Hakyll.Core.Identifier
32import Hakyll.Core.Identifier.Pattern
33import Hakyll.Core.Identifier.Pattern
33import Hakyll.Core.Routes
34import Hakyll.Core.Routes
34import Hakyll.Core.Rules
35import Hakyll.Core.Rules
36+import Hakyll.Core.UnixFilter
35import Hakyll.Core.Util.Arrow
37import Hakyll.Core.Util.Arrow
36import Hakyll.Core.Util.File
38import Hakyll.Core.Util.File
37import Hakyll.Core.Writable
39import Hakyll.Core.Writable
src/Hakyll/Core/UnixFilter.hsnew file+66
@@ -0,0 +1,66 @@
1+-- | A Compiler that supports unix filters.
2+--
3+module Hakyll.Core.UnixFilter
4+ ( unixFilter
5+ ) where
6+
7+import Control.Concurrent (forkIO)
8+import System.IO (hPutStr, hClose, hGetContents)
9+import System.Posix.Process (executeFile, forkProcess)
10+import System.Posix.IO ( dupTo, createPipe, stdInput
11+ , stdOutput, closeFd, fdToHandle
12+ )
13+
14+import Hakyll.Core.Compiler
15+
16+-- | Use a unix filter as compiler. For example, we could use the 'rev' program
17+-- as a compiler.
18+--
19+-- > rev :: Compiler Resource String
20+-- > rev = getResourceString >>> unixFilter "rev" []
21+--
22+-- A more realistic example: one can use this to call, for example, the sass
23+-- compiler on CSS files. More information about sass can be found here:
24+--
25+-- <http://sass-lang.com/>
26+--
27+-- The code is fairly straightforward, given that we use @.scss@ for sass:
28+--
29+-- > route "style.scss" $ setExtension "css"
30+-- > compile "style.scss" $
31+-- > getResourceString >>> unixFilter "sass" ["-s", "--scss"]
32+-- > >>> arr compressCss
33+--
34+unixFilter :: String -- ^ Program name
35+ -> [String] -- ^ Program args
36+ -> Compiler String String -- ^ Resulting compiler
37+unixFilter programName args = unsafeCompiler $ \input -> do
38+ -- Create pipes
39+ (stdinRead, stdinWrite) <- createPipe
40+ (stdoutRead, stdoutWrite) <- createPipe
41+
42+ -- Fork the child
43+ _ <- forkProcess $ do
44+ -- Copy our pipes over the regular stdin/stdout
45+ _ <- dupTo stdinRead stdInput
46+ _ <- dupTo stdoutWrite stdOutput
47+
48+ -- Close the now unneeded file descriptors in the child
49+ mapM_ closeFd [stdinWrite, stdoutRead, stdinRead, stdoutWrite]
50+
51+ -- Execute the program
52+ _ <- executeFile programName True args Nothing
53+ return ()
54+
55+ -- On the parent side, close the client-side FDs.
56+ mapM_ closeFd [stdinRead, stdoutWrite]
57+
58+ -- Write the input to the child pipe
59+ _ <- forkIO $ do
60+ stdinWriteHandle <- fdToHandle stdinWrite
61+ hPutStr stdinWriteHandle input
62+ hClose stdinWriteHandle
63+
64+ -- Receive the output from the child
65+ stdoutReadHandle <- fdToHandle stdoutRead
66+ hGetContents stdoutReadHandle