texrunner-0.0.1.0: src/System/Texrunner.hs
----------------------------------------------------------------------------
-- |
-- Module : System.Texrunner
-- Copyright : (c) 2014 Christopher Chalmers
-- License : BSD-style (see LICENSE)
-- Maintainer : c.chalmers@me.com
--
-- Functions for running Tex.
--
-----------------------------------------------------------------------------
module System.Texrunner
( runTex
, runTex'
, prettyPrintLog
) where
import Control.Applicative
import qualified Data.ByteString.Char8 as C8 hiding (concatMap)
import Data.ByteString.Lazy.Char8 as LC8 hiding (concatMap)
import Data.Maybe
import System.Directory
import System.Environment
import System.Exit
import System.FilePath
import System.IO
import System.IO.Temp
import System.Process
import System.Texrunner.Parse
-- | Same as 'runTex'' but runs Tex in a temporary system directory.
runTex :: String -- ^ Tex command
-> [String] -- ^ Additional arguments
-> [FilePath] -- ^ Additional Tex input paths
-> ByteString -- ^ Source Tex file
-> IO (ExitCode, TexLog, Maybe ByteString)
runTex command args extras source =
withSystemTempDirectory "texrunner." $ \path ->
runTex' path command args extras source
-- | Run Tex program in the given directory. Additional Tex inputs are
-- for filepaths to things like images that Tex can refer to.
runTex' :: FilePath -- ^ Directory to run Tex in
-> String -- ^ Tex command
-> [String] -- ^ Additional arguments
-> [FilePath] -- ^ Additional Tex inputs
-> ByteString -- ^ Source Tex file
-> IO (ExitCode, TexLog, Maybe ByteString)
runTex' path command args extras source = do
LC8.writeFile (path </> "texrunner.tex") source
environment <- extraTexInputs (path:extras) <$> getEnvironment
let p = (proc command ("texrunner.tex" : args))
{ cwd = Just path
, std_in = CreatePipe
, std_out = CreatePipe
, env = Just environment
}
(Just inH, Just outH, _, pHandle) <- createProcess p
hClose inH
a <- C8.hGetContents outH -- backup log
hClose outH
exitC <- waitForProcess pHandle
pdfExists <- doesFileExist (path </> "texrunner.pdf")
pdfFile <- if pdfExists
then Just <$> LC8.readFile (path </> "texrunner.pdf")
else return Nothing
logExists <- doesFileExist (path </> "texrunner.log")
logFile <- if logExists
then Just <$> C8.readFile (path </> "texrunner.log")
else return Nothing
-- pdfFile <- optional $ LC8.readFile (path </> "texrunner.pdf")
-- logFile <- optional $ C8.readFile (path </> "texrunner.log")
return (exitC, parseLog $ fromMaybe a logFile, pdfFile)
-- | Add a list of paths to the tex
extraTexInputs :: [FilePath] -> [(String,String)] -> [(String,String)]
extraTexInputs [] = id
extraTexInputs inputss = alter f "TEXINPUTS"
where
f Nothing = Just inputs
f (Just x) = Just (inputs ++ [searchPathSeparator] ++ x)
--
inputs = concatMap (++ [searchPathSeparator]) inputss
-- inputs = intercalate [searchPathSeparator] inputss
-- Alter can be used to insert, delete or update an element. Similar to alter
-- in Data.Map.
alter :: Eq k => (Maybe a -> Maybe a) -> k -> [(k,a)] -> [(k,a)]
alter f k = go
where
go [] = maybeToList ((,) k <$> f Nothing)
go ((k',x):xs)
| k' == k = case f (Just x) of
Just x' -> (k',x') : xs
Nothing -> xs
| otherwise = (k',x) : go xs