@@ -7,16 +7,24 @@ module Hakyll.Core.UnixFilter
77
88
99--------------------------------------------------------------------------------
10−import Control.Concurrent (forkIO)
11−import Data.ByteString.Lazy (ByteString)
12−import qualified Data.ByteString.Lazy as LB
13−import System.IO (Handle, hClose, hGetContents, hPutStr,
14− hSetEncoding, localeEncoding)
10+import Control.Concurrent (forkIO)
11+import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)
12+import Control.DeepSeq (NFData, deepseq)
13+import Control.Monad (forM_)
14+import Data.ByteString.Lazy (ByteString)
15+import qualified Data.ByteString.Lazy as LB
16+import Data.IORef (newIORef, readIORef, writeIORef)
17+import Data.Monoid (Monoid, mempty)
18+import System.Exit (ExitCode (..))
19+import System.IO (Handle, hClose, hFlush,
20+ hGetContents, hPutStr,
21+ hSetEncoding, localeEncoding)
1522import System.Process
1623
1724
1825--------------------------------------------------------------------------------
1926import Hakyll.Core.Compiler
27+import Hakyll.Core.Compiler.Internal
2028
2129
2230--------------------------------------------------------------------------------
@@ -67,7 +75,8 @@ unixFilterLBS = unixFilterWith LB.hPutStr LB.hGetContents
6775
6876--------------------------------------------------------------------------------
6977-- | Overloaded compiler
70−unixFilterWith :: (Handle -> i -> IO ()) -- ^ Writer
78+unixFilterWith :: (Monoid o, NFData o)
79+ => (Handle -> i -> IO ()) -- ^ Writer
7180 -> (Handle -> IO o) -- ^ Reader
7281 -> String -- ^ Program name
7382 -> [String] -- ^ Program args
@@ -75,31 +84,59 @@ unixFilterWith :: (Handle -> i -> IO ()) -- ^ Writer
7584 -> Compiler o -- ^ Program output
7685unixFilterWith writer reader programName args input = do
7786 debugCompiler ("Executing external program " ++ programName)
78− unsafeCompiler $ unixFilterIO writer reader programName args input
87+ (output, err, exitCode) <- unsafeCompiler $
88+ unixFilterIO writer reader programName args input
89+ forM_ (lines err) debugCompiler
90+ case exitCode of
91+ ExitSuccess -> return output
92+ ExitFailure e -> compilerThrow $
93+ "Hakyll.Core.UnixFilter.unixFilterWith: " ++
94+ unwords (programName : args) ++ " gave exit code " ++ show e
7995
8096
8197--------------------------------------------------------------------------------
8298-- | Internally used function
83−unixFilterIO :: (Handle -> i -> IO ())
99+unixFilterIO :: (Monoid o, NFData o)
100+ => (Handle -> i -> IO ())
84101 -> (Handle -> IO o)
85102 -> String
86103 -> [String]
87104 -> i
88− -> IO o
105+ -> IO (o, String, ExitCode)
89106unixFilterIO writer reader programName args input = do
90− let process = (proc programName args)
91− { std_in = CreatePipe
92− , std_out = CreatePipe
93− , close_fds = True
94− }
107+ (Just inh, Just outh, Just errh, pid) <-
108+ createProcess (proc programName args)
109+ { std_in = CreatePipe
110+ , std_out = CreatePipe
111+ , std_err = CreatePipe
112+ }
95113
96− (Just stdinWriteHandle, Just stdoutReadHandle, _, _) <-
97− createProcess process
114+ -- Create boxes
115+ lock <- newEmptyMVar
116+ outRef <- newIORef mempty
117+ errRef <- newIORef ""
98118
99119 -- Write the input to the child pipe
120+ _ <- forkIO $ writer inh input >> hFlush inh >> hClose inh
121+
122+ -- Read from stdout
123+ _ <- forkIO $ do
124+ out <- reader outh
125+ deepseq out (hClose outh)
126+ writeIORef outRef out
127+ putMVar lock ()
128+
129+ -- Read from stderr
100130 _ <- forkIO $ do
101− writer stdinWriteHandle input
102− hClose stdinWriteHandle
131+ err <- hGetContents errh
132+ deepseq err (hClose errh)
133+ writeIORef errRef err
134+ putMVar lock ()
103135
104− -- Receive the output from the child
105− reader stdoutReadHandle
136+ -- Get exit code & return
137+ takeMVar lock
138+ takeMVar lock
139+ exitCode <- waitForProcess pid
140+ out <- readIORef outRef
141+ err <- readIORef errRef
142+ return (out, err, exitCode)