{-# LANGUAGE ScopedTypeVariables #-}
module Reanimate.Driver.Check
( checkEnvironment
) where
import Control.Exception (SomeException, handle)
import Control.Monad
import Data.Maybe
import Data.Version
import Reanimate.Misc (runCmd_)
import System.Directory (findExecutable)
import System.IO
import System.IO.Temp
import Text.ParserCombinators.ReadP
import qualified Text.PrettyPrint.ANSI.Leijen as Doc
import Text.Printf
checkEnvironment :: IO ()
checkEnvironment = do
putStrLn "reanimate checks:"
runCheck "Has ffmpeg" hasFFmpeg
runCheck "Has LaTeX" hasLaTeX
runCheck "Has XeLaTeX" hasXeLaTeX
runCheck "Has dvisvgm" hasDvisvgm
runCheck "Has povray" hasPovray
runCheck ("Has LaTeX package '"++ "babel" ++ "'") $ hasTeXPackage "latex"
"[english]{babel}"
forM_ latexPackages $ \pkg ->
runCheck ("Has LaTeX package '"++ pkg ++ "'") $ hasTeXPackage "latex" $
"{"++pkg++"}"
forM_ xelatexPackages $ \pkg ->
runCheck ("Has XeLaTeX package '"++ pkg ++ "'") $ hasTeXPackage "xelatex" $
"{"++pkg++"}"
where
latexPackages =
["preview"
,"amsmath"
,"amssymb"
,"dsfont"
,"setspace"
,"relsize"
,"textcomp"
,"mathrsfs"
,"calligra"
,"wasysym"
,"ragged2e"
,"physics"
,"xcolor"
,"textcomp"
,"xfrac"
,"microtype"]
xelatexPackages =
["ctex"]
runCheck msg fn = do
printf " %-35s" (msg ++ ":")
val <- fn
case val of
Left err -> print $ Doc.red $ Doc.text err
Right ok -> print $ Doc.green $ Doc.text ok
hasLaTeX :: IO (Either String String)
hasLaTeX = hasProgram "latex"
hasXeLaTeX :: IO (Either String String)
hasXeLaTeX = hasProgram "xelatex"
hasDvisvgm :: IO (Either String String)
hasDvisvgm = hasProgram "dvisvgm"
hasPovray :: IO (Either String String)
hasPovray = hasProgram "povray"
hasFFmpeg :: IO (Either String String)
hasFFmpeg = do
mbVersion <- ffmpegVersion
return $ case mbVersion of
Nothing -> Left "no"
Just vs | vs < minVersion -> Left $ "too old: " ++ showVersion vs ++ " < " ++ showVersion minVersion
| otherwise -> Right (showVersion vs)
where
minVersion = Version [4,1,3] []
ffmpegVersion :: IO (Maybe Version)
ffmpegVersion = do
mbPath <- findExecutable "ffmpeg"
case mbPath of
Nothing -> return Nothing
Just path -> do
ret <- runCmd_ path ["-version"]
case ret of
Left{} -> return $ Just noVersion
Right out ->
case map (take 3 . words) $ take 1 $ lines out of
[["ffmpeg", "version", vs]] ->
return $ Just $ fromMaybe noVersion $ parseVS vs
_ -> return $ Just noVersion
where
noVersion = Version [] []
parseVS vs = listToMaybe $ reverse
[ v | (v, _) <- readP_to_S parseVersion vs ]
hasTeXPackage :: FilePath -> String -> IO (Either String String)
hasTeXPackage exec pkg = handle (\(_::SomeException) -> return $ Left "n/a") $
withSystemTempDirectory "reanimate" $ \tmp_dir -> withTempFile tmp_dir "test.tex" $ \tex_file tex_handle -> do
hPutStr tex_handle tex_document
hPutStr tex_handle $ "\\usepackage" ++ pkg ++ "\n"
hPutStr tex_handle "\\begin{document}\n"
hPutStr tex_handle "blah\n"
hPutStr tex_handle tex_epilogue
hClose tex_handle
ret <- runCmd_ exec ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
return $ case ret of
Right{} -> Right "OK"
Left{} -> Left "missing"
where
tex_document = "\\documentclass[preview]{standalone}\n"
tex_epilogue =
"\n\
\\\end{document}"
hasProgram :: String -> IO (Either String String)
hasProgram exec = do
mbPath <- findExecutable exec
return $ case mbPath of
Nothing -> Left $ "'" ++ exec ++ "'' not found"
Just path -> Right path