never executed always true always false
1 {-# LANGUAGE ScopedTypeVariables #-}
2 module Reanimate.Driver.Check
3 ( checkEnvironment
4 , hasRSvg
5 , hasInkscape
6 , hasMagick
7 , hasFFmpegRSvg
8 ) where
9
10 import Control.Exception (SomeException, handle)
11 import Control.Monad
12 import Data.Maybe
13 import Data.Version
14 import Reanimate.Misc (runCmd_)
15 import Reanimate.Driver.Magick (magickCmd)
16 import System.Console.ANSI.Codes
17 import System.Directory (findExecutable)
18 import System.IO
19 import System.IO.Temp
20 import Text.ParserCombinators.ReadP
21 import Text.Printf
22
23 --------------------------------------------------------------------------
24 -- Check environment
25
26 checkEnvironment :: IO ()
27 checkEnvironment = do
28 putStrLn "reanimate checks:"
29 runCheck "Has ffmpeg" hasFFmpeg
30 runCheck "Has ffmpeg(rsvg)" hasFFmpegRSvg
31 runCheck "Has dvisvgm" hasDvisvgm
32 runCheck "Has povray" hasPovray
33 runCheck "Has blender" hasBlender
34 runCheck "Has rsvg-convert" hasRSvg
35 runCheck "Has inkscape" hasInkscape
36 runCheck "Has imagemagick" hasMagick
37 runCheck "Has LaTeX" hasLaTeX
38 runCheck ("Has LaTeX package '"++ "babel" ++ "'") $ hasTeXPackage "latex"
39 "[english]{babel}"
40 forM_ latexPackages $ \pkg ->
41 runCheck ("Has LaTeX package '"++ pkg ++ "'") $ hasTeXPackage "latex" $
42 "{"++pkg++"}"
43 runCheck "Has XeLaTeX" hasXeLaTeX
44 forM_ xelatexPackages $ \pkg ->
45 runCheck ("Has XeLaTeX package '"++ pkg ++ "'") $ hasTeXPackage "xelatex" $
46 "{"++pkg++"}"
47 where
48 latexPackages =
49 ["preview"
50 ,"amsmath"
51 --,"amssymb"
52 --,"dsfont"
53 --,"setspace"
54 --,"relsize"
55 --,"textcomp"
56 --,"mathrsfs"
57 --,"calligra"
58 --,"wasysym"
59 --,"ragged2e"
60 --,"physics"
61 --,"xcolor"
62 --,"textcomp"
63 --,"xfrac"
64 --,"microtype"
65 ]
66 xelatexPackages =
67 ["ctex"]
68 runCheck msg fn = do
69 printf " %-35s" (msg ++ ":")
70 val <- fn
71 case val of
72 Left err -> putStrLnColor Red err
73 Right ok -> putStrLnColor Green ok
74
75 putStrLnColor :: Color -> String -> IO ()
76 putStrLnColor color msg =
77 putStrLn $ setSGRCode [SetColor Foreground Vivid color] ++ msg ++ setSGRCode [Reset]
78
79 -- latex, dvisvgm, xelatex
80
81 hasLaTeX :: IO (Either String String)
82 hasLaTeX = hasProgram "latex"
83
84 hasXeLaTeX :: IO (Either String String)
85 hasXeLaTeX = hasProgram "xelatex"
86
87 hasDvisvgm :: IO (Either String String)
88 hasDvisvgm = hasProgram "dvisvgm"
89
90 hasPovray :: IO (Either String String)
91 hasPovray = hasProgram "povray"
92
93 hasFFmpeg :: IO (Either String String)
94 hasFFmpeg = checkMinVersion minVersion <$> ffmpegVersion
95 where
96 minVersion = Version [4,1,3] []
97
98 hasFFmpegRSvg :: IO (Either String String)
99 hasFFmpegRSvg = do
100 mbPath <- findExecutable "ffmpeg"
101 case mbPath of
102 Nothing -> return $ Left "n/a"
103 Just path -> do
104 ret <- runCmd_ path ["-version"]
105 pure $ case ret of
106 Right out | "--enable-librsvg" `elem` words out
107 -> Right "yes"
108 _ -> Left "no"
109
110 hasBlender :: IO (Either String String)
111 hasBlender = checkMinVersion minVersion <$> blenderVersion
112 where
113 minVersion = Version [2,80] []
114
115 hasRSvg :: IO (Either String String)
116 hasRSvg = checkMinVersion minVersion <$> rsvgVersion
117 where
118 minVersion = Version [2,44,0] []
119
120 hasInkscape :: IO (Either String String)
121 hasInkscape = checkMinVersion minVersion <$> inkscapeVersion
122 where
123 minVersion = Version [0,92] []
124
125 hasMagick :: IO (Either String String)
126 hasMagick = checkMinVersion minVersion <$> magickVersion
127 where
128 minVersion = Version [6,0,0] []
129
130 ffmpegVersion :: IO (Maybe Version)
131 ffmpegVersion = extractVersion "ffmpeg" ["-version"] $ \line ->
132 case take 3 $ words line of
133 ["ffmpeg", "version", vs] -> vs
134 _ -> ""
135
136 blenderVersion :: IO (Maybe Version)
137 blenderVersion = extractVersion "blender" ["--version"] $ \line ->
138 case take 2 (words line) of
139 ["Blender", vs] -> vs
140 _ -> ""
141
142 rsvgVersion :: IO (Maybe Version)
143 rsvgVersion = extractVersion "rsvg-convert" ["--version"] $ \line ->
144 case words line of
145 ["rsvg-convert", "version", vs] -> vs
146 _ -> ""
147
148 inkscapeVersion :: IO (Maybe Version)
149 inkscapeVersion = extractVersion "inkscape" ["--version"] $ \line ->
150 case take 2 $ words line of
151 ["Inkscape", vs] -> vs
152 _ -> ""
153
154 magickVersion :: IO (Maybe Version)
155 magickVersion = extractVersion magickCmd ["-version"] $ \line ->
156 case take 3 $ words line of
157 ["Version:", "ImageMagick", vs] -> vs
158 _ -> ""
159
160 checkMinVersion :: Version -> Maybe Version -> Either String String
161 checkMinVersion _minVersion Nothing = Left "no"
162 checkMinVersion minVersion (Just vs)
163 | vs < minVersion = Left $ "too old: " ++ showVersion vs ++ " < " ++ showVersion minVersion
164 | otherwise = Right (showVersion vs)
165
166 extractVersion :: FilePath -> [String] -> (String -> String) -> IO (Maybe Version)
167 extractVersion execPath args outputFilter = do
168 mbPath <- findExecutable execPath
169 case mbPath of
170 Nothing -> return Nothing
171 Just path -> do
172 ret <- runCmd_ path args
173 case ret of
174 Left{} -> return $ Just noVersion
175 Right out ->
176 pure $ Just $ fromMaybe noVersion $ parseVS $ outputFilter out
177 where
178 noVersion = Version [] []
179 parseVS vs = listToMaybe $ reverse
180 [ v | (v, _) <- readP_to_S parseVersion vs ]
181
182 hasTeXPackage :: FilePath -> String -> IO (Either String String)
183 hasTeXPackage exec pkg = handle (\(_::SomeException) -> return $ Left "n/a") $
184 withSystemTempDirectory "reanimate" $ \tmp_dir -> withTempFile tmp_dir "test.tex" $ \tex_file tex_handle -> do
185 hPutStr tex_handle tex_document
186 hPutStr tex_handle $ "\\usepackage" ++ pkg ++ "\n"
187 hPutStr tex_handle "\\begin{document}\n"
188 hPutStr tex_handle "blah\n"
189 hPutStr tex_handle tex_epilogue
190 hClose tex_handle
191 ret <- runCmd_ exec ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
192 return $ case ret of
193 Right{} -> Right "OK"
194 Left{} -> Left "missing"
195 where
196 tex_document = "\\documentclass[preview]{standalone}\n"
197 tex_epilogue =
198 "\n\
199 \\\end{document}"
200
201 hasProgram :: String -> IO (Either String String)
202 hasProgram exec = do
203 mbPath <- findExecutable exec
204 return $ case mbPath of
205 Nothing -> Left $ "'" ++ exec ++ "' not found"
206 Just path -> Right path