module Web.Herringbone.Preprocessor.StdIO (
    makeStdIOPP
) where

import Control.Monad.IO.Class
import Data.Monoid
import Data.Text (Text)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import System.Exit
import System.Process.ByteString
import Web.Herringbone

-- | Make a preprocessor which works over standard IO; reading input from
-- stdin, and writing output to stdout.
makeStdIOPP :: Text     -- ^ File extension
            -> String   -- ^ Program name
            -> [String] -- ^ Arguments
            -> PP
makeStdIOPP ext progname args = PP
    { ppExtension = ext
    , ppAction = compile progname args
    }
    
compile :: String
        -> [String]
        -> ByteString
        -> PPM (Either CompileError ByteString)
compile progname args source = do
    liftIO $ readAllFromProcess progname args source

-- | Read from a process returning both std err and out.
readAllFromProcess :: String        -- ^ Program
                   -> [String]      -- ^ Args
                   -> ByteString    -- ^ Stdin
                   -> IO (Either ByteString ByteString)
readAllFromProcess program flags input = do
  (code,out,err) <- readProcessWithExitCode program flags input
  return $ case code of
    ExitFailure 127 -> Left $ "cannot find executable " <> C8.pack program
    ExitFailure _ -> Left $ join (err, out)
    ExitSuccess -> Right $ join (err, out)
  where
  join (err, out) = if B.null err
                        then out
                        else err <> "\n" <> out