packages feed

pandoc-plot 1.0.2.0 → 1.0.2.1

raw patch · 7 files changed

+69/−39 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Text.Pandoc.Filter.Plot.Internal: throwError :: Text -> PlotM ()
+ Text.Pandoc.Filter.Plot.Internal: mapConcurrentlyN :: Traversable t => Int -> (a -> PlotM b) -> t a -> PlotM (t b)
+ Text.Pandoc.Filter.Plot.Internal: throwStrictError :: Text -> PlotM ()

Files

CHANGELOG.md view
@@ -2,6 +2,12 @@ 
 pandoc-plot uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
 
+Release 1.0.2.1
+---------------
+
+* `pandoc-plot` will now only render at most `N` figures in parallel, where `N` is the number of available CPU cores.
+* Fixed an issue where error message would get mangled in strict-mode.
+
 Release 1.0.2.0
 ---------------
 
pandoc-plot.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.2
 name:           pandoc-plot
-version:        1.0.2.0
+version:        1.0.2.1
 synopsis:       A Pandoc filter to include figures generated from code blocks using your plotting toolkit of choice.
 description:    A Pandoc filter to include figures generated from code blocks. 
                 Keep the document and code in the same location. Output is 
@@ -14,7 +14,7 @@ license:        GPL-2.0-or-later
 license-file:   LICENSE
 build-type:     Simple
-tested-with:    GHC == 8.10.1
+tested-with:    GHC == 8.10.3
 extra-source-files:
     CHANGELOG.md
     LICENSE
src/Text/Pandoc/Filter/Plot.hs view
@@ -109,7 +109,7 @@   )
 where
 
-import Control.Concurrent.Async.Lifted (mapConcurrently)
+import Control.Concurrent (getNumCapabilities)
 import Data.Functor ((<&>))
 import Data.Text (Text, pack, unpack)
 import Data.Version (Version)
@@ -130,12 +130,14 @@     availableToolkits,
     cleanOutputDirs,
     configuration,
+    debug,
     defaultConfiguration,
+    mapConcurrentlyN,
     parseFigureSpec,
     runPlotM,
     runScriptIfNecessary,
     supportedSaveFormats,
-    throwError,
+    throwStrictError,
     toFigure,
     toolkits,
     unavailableToolkits,
@@ -154,8 +156,11 @@   -- | Input document
   Pandoc ->
   IO Pandoc
-plotTransform conf (Pandoc meta blocks) =
-  runPlotM conf $ mapConcurrently make blocks <&> Pandoc meta
+plotTransform conf (Pandoc meta blocks) = do
+  maxproc <- getNumCapabilities
+  runPlotM conf $ do
+    debug $ mconcat ["Starting a new run, utilizing at most ", pack . show $ maxproc, " processes."]
+    mapConcurrentlyN maxproc make blocks <&> Pandoc meta
 
 -- | The version of the pandoc-plot package.
 --
@@ -170,7 +175,7 @@   where
     onError :: Block -> PandocPlotError -> PlotM Block
     onError b e = do
-      whenStrict $ throwError $ "[strict mode] " <> (pack . show $ e)
+      whenStrict $ throwStrictError (pack . show $ e)
       return b
 
 -- | Try to process the block with `pandoc-plot`, documenting the error.
src/Text/Pandoc/Filter/Plot/Monad.hs view
@@ -16,13 +16,16 @@     PlotState (..),
     runPlotM,
 
+    -- * Concurrent execution
+    mapConcurrentlyN,
+
     -- * Running external commands
     runCommand,
     withPrependedPath,
 
     -- * Halting pandoc-plot
     whenStrict,
-    throwError,
+    throwStrictError,
 
     -- * Getting file hashes
     fileHash,
@@ -50,9 +53,11 @@   )
 where
 
+import Control.Concurrent.Async.Lifted (mapConcurrently)
 import Control.Concurrent.Chan (writeChan)
 import Control.Concurrent.MVar
-import Control.Exception.Lifted (bracket)
+import Control.Concurrent.QSemN
+import Control.Exception.Lifted (bracket, bracket_)
 import Control.Monad.Reader
 import Control.Monad.State.Strict
 import Data.ByteString.Lazy (toStrict)
@@ -71,7 +76,7 @@     getModificationTime,
   )
 import System.Environment (getEnv, setEnv)
-import System.Exit (ExitCode (..))
+import System.Exit (ExitCode (..), exitFailure)
 import System.Process.Typed
   ( byteStringInput,
     byteStringOutput,
@@ -117,11 +122,21 @@   withLogger verbosity sink $
     \logger -> runReaderT (evalStateT v st) (RuntimeEnv conf logger cwd)
 
+-- | maps a function, performing at most @N@ actions concurrently.
+mapConcurrentlyN :: Traversable t => Int -> (a -> PlotM b) -> t a -> PlotM (t b)
+mapConcurrentlyN n f xs = do
+  -- Emulating a pool of processes with locked access
+  sem <- liftIO $ newQSemN n
+  mapConcurrently (with sem . f) xs
+  where
+    with :: QSemN -> PlotM a -> PlotM a
+    with s = bracket_ (liftIO $ waitQSemN s 1) (liftIO $ signalQSemN s 1)
+
 debug, err, warning, info :: Text -> PlotM ()
-debug = log "DEBUG | " Debug
-err = log "ERROR | " Error
-warning = log "WARN  | " Warning
-info = log "INFO  | " Info
+debug = log "[pandoc-plot] DEBUG | " Debug
+err = log "[pandoc-plot] ERROR | " Error
+warning = log "[pandoc-plot] WARN  | " Warning
+info = log "[pandoc-plot] INFO  | " Info
 
 -- | General purpose logging.
 log ::
@@ -198,9 +213,14 @@     (\_ -> liftIO $ setEnv "PATH" pathVar)
     (const f)
 
--- | Throw an error that halts the execution of pandoc-plot
-throwError :: Text -> PlotM ()
-throwError = liftIO . errorWithoutStackTrace . unpack
+-- | Throw an error that halts the execution of pandoc-plot due to a strict-mode.
+throwStrictError :: Text -> PlotM ()
+throwStrictError msg = do
+  logger <- asks envLogger
+  log "[pandoc-plot] STRICT MODE | " Error msg
+  liftIO $ do
+    terminateLogging logger
+    exitFailure
 
 -- | Conditional execution of a PlotM action if pandoc-plot is
 -- run in strict mode.
src/Text/Pandoc/Filter/Plot/Monad/Logging.hs view
@@ -15,20 +15,21 @@     LogSink (..),
     Logger (..),
     withLogger,
+    terminateLogging,
   )
 where
 
 import Control.Concurrent (forkIO)
 import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
 import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
-import Control.Monad (forever)
+import Control.Monad (forever, void)
 import Data.Char (toLower)
 import Data.List (intercalate)
 import Data.String (IsString (..))
 import Data.Text (Text, unpack)
-import Data.Text.IO (hPutStr)
+import Data.Text.IO as TIO
 import Data.Yaml (FromJSON (parseJSON), Value (String))
-import System.IO (IOMode (AppendMode), stderr, withFile)
+import System.IO (stderr)
 
 -- | Verbosity of the logger.
 data Verbosity
@@ -60,6 +61,16 @@     lSync :: MVar ()
   }
 
+-- | Ensure that all log messages are flushed, and stop logging
+terminateLogging :: Logger -> IO ()
+terminateLogging logger = do
+  -- Flushing the logger
+  -- To signal to the logger that logging duties are over,
+  -- we append Nothing to the channel, and wait for it to finish
+  -- dealing with all items in the channel.
+  writeChan (lChannel logger) Nothing
+  void $ takeMVar (lSync logger)
+
 -- | Perform an IO action with a logger. Using this function
 -- ensures that logging will be gracefully shut down.
 withLogger :: Verbosity -> LogSink -> (Logger -> IO a) -> IO a
@@ -80,17 +91,13 @@ 
   result <- f logger
 
-  -- Flushing the logger
-  -- To signal to the logger that logging duties are over,
-  -- we append Nothing to the channel, and wait for it to finish
-  -- dealing with all items in the channel.
-  writeChan (lChannel logger) Nothing
-  () <- takeMVar (lSync logger)
+  terminateLogging logger
 
   return result
   where
-    sink StdErr = hPutStr stderr
-    sink (LogFile fp) = \t -> withFile fp AppendMode $ \h -> hPutStr h t
+    sink :: LogSink -> Text -> IO ()
+    sink StdErr = TIO.hPutStr stderr
+    sink (LogFile fp) = TIO.appendFile fp
 
 instance IsString Verbosity where
   fromString s
@@ -109,4 +116,4 @@ 
 instance FromJSON Verbosity where
   parseJSON (String t) = pure $ fromString . unpack $ t
-  parseJSON _ = fail $ "Could not parse the logging verbosity."
+  parseJSON _ = fail "Could not parse the logging verbosity."
src/Text/Pandoc/Filter/Plot/Parse.hs view
@@ -61,7 +61,7 @@       case r of
         Nothing -> do
           let msg = mconcat ["Renderer for ", tshow tk, " needed but is not installed"]
-          whenStrict $ throwError $ "[strict mode] " <> msg
+          whenStrict $ throwStrictError msg
           warning msg
           return Nothing
         Just r' -> do
stack.yaml view
@@ -1,22 +1,14 @@-resolver: nightly-2020-12-14 # GHC 8.10.2
+resolver: nightly-2021-01-05 # GHC 8.10.3
 
 packages:
 - .
 
-# GHC 8.10.2 is broken on Windows:
-#   https://gitlab.haskell.org/ghc/ghc/-/issues/18550
-compiler: ghc-8.10.3
-
 extra-deps:
 - pandoc-2.11.3.2
 - citeproc-0.3.0.3@sha256:273b4935b18079fb666e53419dbf31e1edb7c7bdf7ea4295ff7ba6da22dc61b3,5590
-- texmath-0.12.1@sha256:57d2ff00f89da2a56f10eda28c6c502e1314a35090c7f63600f6d7b0adedbc29,6563
 - commonmark-0.1.1.2@sha256:c06ab05f0f224ab7982502a96e17952823a9b6dae8505fb35194b0baa9e2a975,3278
 - commonmark-extensions-0.2.0.4@sha256:6a437bcfa3c757af4262b71336513619990eafb5cfdc33e57a499c93ad225608,3184
 - commonmark-pandoc-0.2.0.1@sha256:529c6e2c6cabf61558b66a28123eafc1d90d3324be29819f59f024e430312c1f,1105
-- doctemplates-0.9@sha256:eb0bf957ba8571746f36f07ceca43d311a0e390a9fdcfde6909f9f9be85b3b28,3125
-- skylighting-0.10.2@sha256:9c395703ca61752f4491044443e87d5b87ed94bca78c0a00b5ebf4e4b8e59904,10031
-- skylighting-core-0.10.2@sha256:5070d9f08135cdb7c935c5936a4a76a9e1922ec846cd40d6e2837f42e7a9f29f,8159
 
 # For development
 - git: https://github.com/owickstrom/pandoc-include-code.git