summaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/Filter/Pyplot/Scripting.hs
diff options
context:
space:
mode:
authorLaurentRDC <>2019-05-29 19:39:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2019-05-29 19:39:00 (GMT)
commitea33899f29e83431ba6ff02c9c2acf172bc75384 (patch)
tree4c5b2443a704c59a5d7082a7eb5fd1f6ceaae4a9 /src/Text/Pandoc/Filter/Pyplot/Scripting.hs
parentd0b25ab26c2ecc6ab5e94a4fbda855615cdd60fa (diff)
version 2.1.2.02.1.2.0
Diffstat (limited to 'src/Text/Pandoc/Filter/Pyplot/Scripting.hs')
-rw-r--r--src/Text/Pandoc/Filter/Pyplot/Scripting.hs86
1 files changed, 61 insertions, 25 deletions
diff --git a/src/Text/Pandoc/Filter/Pyplot/Scripting.hs b/src/Text/Pandoc/Filter/Pyplot/Scripting.hs
index d867363..0ed4642 100644
--- a/src/Text/Pandoc/Filter/Pyplot/Scripting.hs
+++ b/src/Text/Pandoc/Filter/Pyplot/Scripting.hs
@@ -13,47 +13,83 @@ with running Python scripts.
-}
module Text.Pandoc.Filter.Pyplot.Scripting
( runTempPythonScript
- , hasBlockingShowCall
+ , runScriptIfNecessary
) where
import Data.Hashable (hash)
-import Data.Monoid (Any(..))
+import Data.List (intersperse)
+import Data.Monoid (Any(..), (<>))
import qualified Data.Text as T
import qualified Data.Text.IO as T
+import System.Directory (createDirectoryIfMissing,
+ doesFileExist)
import System.Exit (ExitCode (..))
-import System.FilePath ((</>))
+import System.FilePath ((</>), takeDirectory)
import System.IO.Temp (getCanonicalTemporaryDirectory)
import System.Process.Typed (runProcess, shell)
import Text.Pandoc.Filter.Pyplot.Types
+import Text.Pandoc.Filter.Pyplot.FigureSpec
+
+-- | Detect the presence of a blocking show call, for example "plt.show()"
+checkBlockingShowCall :: PythonScript -> CheckResult
+checkBlockingShowCall script' =
+ if hasShowCall
+ then CheckFailed "The script has a blocking call to `matplotlib.pyplot.show`. "
+ else CheckPassed
+ where
+ scriptLines = T.lines script'
+ hasShowCall = getAny $ mconcat $ Any <$>
+ [ "plt.show()" `elem` scriptLines
+ , "pyplot.show()" `elem` scriptLines
+ , "matplotlib.pyplot.show()" `elem` scriptLines
+ ]
+
+-- | List of all script checks
+-- This might be overkill right now but extension to other languages will be easier
+scriptChecks :: [PythonScript -> CheckResult]
+scriptChecks = [checkBlockingShowCall]
-- | Take a python script in string form, write it in a temporary directory,
-- then execute it.
runTempPythonScript :: String -- ^ Interpreter (e.g. "python" or "python35")
+ -> [String] -- ^ Command-line flags
-> PythonScript -- ^ Content of the script
- -> IO ScriptResult -- ^ Result with exit code.
-runTempPythonScript interpreter' script' = do
- -- We involve the script hash as a temporary filename
- -- so that there is never any collision
- scriptPath <- (</> hashedPath) <$> getCanonicalTemporaryDirectory
- T.writeFile scriptPath script'
-
- ec <- runProcess $ shell $ mconcat [interpreter', " ", show scriptPath]
- case ec of
- ExitSuccess -> return ScriptSuccess
- ExitFailure code -> return $ ScriptFailure code
+ -> IO ScriptResult -- ^ Result.
+runTempPythonScript interpreter' flags' script' = case checkResult of
+ CheckFailed msg -> return $ ScriptChecksFailed msg
+ CheckPassed -> do
+ -- We involve the script hash as a temporary filename
+ -- so that there is never any collision
+ scriptPath <- (</> hashedPath) <$> getCanonicalTemporaryDirectory
+ T.writeFile scriptPath script'
+
+ let command = mconcat . intersperse " " $ [interpreter'] <> flags' <> [show scriptPath]
+
+ ec <- runProcess . shell $ command
+ case ec of
+ ExitSuccess -> return ScriptSuccess
+ ExitFailure code -> return $ ScriptFailure code
where
+ checkResult = mconcat $ scriptChecks <*> [script']
hashedPath = show . hash $ script'
--- | Detect the presence of a blocking show call, for example "plt.show()"
-hasBlockingShowCall :: PythonScript -> Bool
-hasBlockingShowCall script' =
- anyOf
- [ "plt.show()" `elem` scriptLines
- , "pyplot.show()" `elem` scriptLines
- , "matplotlib.pyplot.show()" `elem` scriptLines
- ]
- where
- scriptLines = T.lines script'
- anyOf xs = getAny $ mconcat $ Any <$> xs \ No newline at end of file
+-- | Run the Python script. In case the file already exists, we can safely assume
+-- there is no need to re-run it.
+runScriptIfNecessary :: Configuration -> FigureSpec -> IO ScriptResult
+runScriptIfNecessary config spec = do
+ createDirectoryIfMissing True . takeDirectory $ figurePath spec
+
+ fileAlreadyExists <- doesFileExist $ figurePath spec
+ result <- if fileAlreadyExists
+ then return ScriptSuccess
+ else runTempPythonScript (interpreter config) (flags config) scriptWithCapture
+
+ case result of
+ ScriptSuccess -> T.writeFile (sourceCodePath spec) (script spec) >> return ScriptSuccess
+ ScriptFailure code -> return $ ScriptFailure code
+ ScriptChecksFailed msg -> return $ ScriptChecksFailed msg
+
+ where
+ scriptWithCapture = addPlotCapture spec \ No newline at end of file