Skip to content

Commit b850c16

Browse files
committed
Fix an issue where multiple identical figures would result in a race condition to write to the same output file (#53)
1 parent bd3411a commit b850c16

File tree

5 files changed

+67
-5
lines changed

5 files changed

+67
-5
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ jobs:
187187
exit 1
188188
fi
189189
pandoc-plot clean tests/issue46.md
190+
191+
pandoc --filter pandoc-plot -i tests/issue53.md -t native
192+
if [ $(ls "plots" | wc -l) != 2 ]; then
193+
exit 1
194+
fi
195+
pandoc-plot clean tests/issue53.md
190196
191197
- name: Build documentation
192198
run: source tools/mkmanual.sh

src/Text/Pandoc/Filter/Plot/Monad.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ data RuntimeEnv = RuntimeEnv
126126
{ envFormat :: Maybe Format, -- pandoc output format
127127
envConfig :: Configuration,
128128
envLogger :: Logger,
129-
envCWD :: FilePath
129+
envCWD :: FilePath,
130+
-- The following lock prevents from writing to the same file multiple times.
131+
-- This is a rather crude fix for issue #53.
132+
envIOLock :: MVar ()
130133
}
131134

132135
-- | Get access to configuration within the @PlotM@ monad.
@@ -137,12 +140,13 @@ asksConfig f = asks (f . envConfig)
137140
runPlotM :: Maybe Format -> Configuration -> PlotM a -> IO a
138141
runPlotM fmt conf v = do
139142
cwd <- getCurrentDirectory
143+
sem <- newMVar ()
140144
st <-
141145
PlotState <$> newMVar mempty
142146
let verbosity = logVerbosity conf
143147
sink = logSink conf
144148
withLogger verbosity sink $
145-
\logger -> runReaderT (evalStateT v st) (RuntimeEnv fmt conf logger cwd)
149+
\logger -> runReaderT (evalStateT v st) (RuntimeEnv fmt conf logger cwd sem)
146150

147151
-- | maps a function, performing at most @N@ actions concurrently.
148152
mapConcurrentlyN :: Traversable t => Int -> (a -> PlotM b) -> t a -> PlotM (t b)

src/Text/Pandoc/Filter/Plot/Renderers.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ availableToolkitsM = asNonStrictAndSilent $ do
149149
else return Nothing
150150
return $ catMaybes mtks
151151
where
152-
asNonStrictAndSilent = local (\(RuntimeEnv f c l d) -> RuntimeEnv f (c{strictMode = False}) (l{lVerbosity = Silent}) d)
152+
asNonStrictAndSilent = local (\(RuntimeEnv f c l d s) -> RuntimeEnv f (c{strictMode = False}) (l{lVerbosity = Silent}) d s)
153153

154154
-- | Check that the supplied command results in
155155
-- an exit code of 0 (i.e. no errors)

src/Text/Pandoc/Filter/Plot/Scripting.hs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Text.Pandoc.Filter.Plot.Scripting
2020
)
2121
where
2222

23+
import Control.Concurrent.MVar (withMVar)
2324
import Data.Default (def)
2425
import Data.Functor.Identity (Identity (..))
2526
import Data.Hashable (hash)
@@ -114,7 +115,11 @@ runTempScript spec@FigureSpec {..} = do
114115

115116
let scriptWithCapture = rendererCapture renderer_ spec target
116117

117-
liftIO $ T.writeFile scriptPath scriptWithCapture
118+
-- Note the use of a lock. This is a crude solution for issue #53, where
119+
-- multiple identical figures can cause a race condition to write to the
120+
-- same output file.
121+
sem <- asks envIOLock
122+
liftIO $ withMVar sem $ \_ -> T.writeFile scriptPath scriptWithCapture
118123
let outputSpec =
119124
OutputSpec
120125
{ oFigureSpec = spec,
@@ -200,7 +205,12 @@ writeSource spec = do
200205
-- Note that making the document self-contained is absolutely required so that the CSS for
201206
-- syntax highlighting is included directly in the document.
202207
t = either (const mempty) id $ runPure (writeHtml5String opts doc >>= makeSelfContained)
203-
liftIO $ T.writeFile scp t
208+
209+
-- Note the use of a lock. This is a crude solution for issue #53, where
210+
-- multiple identical figures can cause a race condition to write to the
211+
-- same output file.
212+
sem <- asks envIOLock
213+
liftIO $ withMVar sem $ \_ -> T.writeFile scp t
204214

205215
either (err . pack) renderSource $ runIdentity $ compileTemplate mempty sourceTemplate
206216

tests/issue53.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
3+
```{.python .matplotlib}
4+
import matplotlib.pyplot as plt
5+
plt.plot([1,2,3,4,5])
6+
```
7+
8+
9+
```{.python .matplotlib}
10+
import matplotlib.pyplot as plt
11+
plt.plot([1,2,3,4,5])
12+
```
13+
14+
15+
```{.python .matplotlib}
16+
import matplotlib.pyplot as plt
17+
plt.plot([1,2,3,4,5])
18+
```
19+
20+
21+
```{.python .matplotlib}
22+
import matplotlib.pyplot as plt
23+
plt.plot([1,2,3,4,5])
24+
```
25+
26+
27+
```{.python .matplotlib}
28+
import matplotlib.pyplot as plt
29+
plt.plot([1,2,3,4,5])
30+
```
31+
32+
33+
```{.python .matplotlib}
34+
import matplotlib.pyplot as plt
35+
plt.plot([1,2,3,4,5])
36+
```
37+
38+
39+
```{.python .matplotlib}
40+
import matplotlib.pyplot as plt
41+
plt.plot([1,2,3,4,5])
42+
```

0 commit comments

Comments
 (0)