pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.14k stars 108 forks source link

Externalize save md5 even if the build fails, so compiling twice does not produce errors while it should #1137

Open tobiasBora opened 2 years ago

tobiasBora commented 2 years ago

Brief outline of the bug

If you compile a figure using the external library and update it afterwards by including an error, you will get an error the first time (as expected)... But if you recompile, instead of having an error, the old (non-updated) picture will be used instead. The reason seems to be that the .md5 file is updated even if the build fails. On the next run, therefore the .md5 sum matches so tikz does not recompile the picture, and uses instead the old picture that compiled before.

I guess the solution is to push the code that modifies the .md5 file after the compilation. This way, if the compilation fails the md5 sum is not updated, and tikz tries to recompile the file.

Minimal working example (MWE) First compile this document with pdflatex -shell-escape.

\documentclass[]{article}

\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\tikzset{external/system call={pdflatex \tikzexternalcheckshellescape -jobname "\image" "\texsource"}}

\begin{document}

\begin{tikzpicture}
  \node (A) {A};
  \node (B) at (1,1) {B};
  %% Line to comment after the first compilation
  \node (C) at (1,0) {C};
  \draw (A) -- (C);
\end{tikzpicture}

\end{document}

Then, comment the line \node (C) at (1,0) {C};. You will get an error. Stop the compilation (with Ctrl+D for instance), and recompile. No more errors, for no reasons!

Meanwhile, if you inspect the file-figure0.md5 file, you will see that the md5 got updated.

hmenke commented 2 years ago

It's a lot less easy than that. First of all I don't know whether it's even possible to detect the return code of a \write18 within TeX and then there is the added problem that if the externalized figure contains references, compilation has to be deferred until \end{document} and therefore the md5 update with it.

hmenke commented 2 years ago

Here is a wild guess which is completely untested.

diff --git a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzexternalshared.code.tex b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzexternalshared.code.tex
index 2ff5aa2d..c0d65407 100644
--- a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzexternalshared.code.tex
+++ b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzexternalshared.code.tex
@@ -1592,9 +1592,6 @@
             \tikzexternal@file@isuptodatetrue
         \else
             \tikzexternal@file@isuptodatefalse
-            \immediate\openout\w@pgf@writea=\tikzexternal@curfilename\tikzexternal@check@uptodate@ext\relax%
-            \immediate\write\w@pgf@writea{\tikzexternal@hashfct@serialize{\tikzexternal@lastkey@new}\tikzexternal@PERCENTchar}%
-            \immediate\closeout\w@pgf@writea
         \fi
     \fi
 }
@@ -1630,6 +1627,13 @@
     \pgf@tempa
     \ifx\pgf@filename\pgfutil@empty%
         \tikzexternal@externalizefig@systemcall@handleexception{#1}%
+    \else
+        % update md5 after successful compilation
+        \ifx\tikzexternal@hashfct\pgfutil@empty\else
+            \immediate\openout\w@pgf@writea=\tikzexternal@curfilename\tikzexternal@check@uptodate@ext\relax%
+            \immediate\write\w@pgf@writea{\tikzexternal@hashfct@serialize{\tikzexternal@lastkey@new}\tikzexternal@PERCENTchar}%
+            \immediate\closeout\w@pgf@writea
+        \fi
     \fi
 }%
 \def\tikzexternal@externalizefig@systemcall@handleexception@msg#1{%
tobiasBora commented 2 years ago

Thanks a lot for your proposition! I'm not sure how I could try that myself, but I can't wait to see this merged ;-) Also, I guess if the issue https://github.com/pgf-tikz/pgf/issues/758 is resolved by renaming files, it would also solve this issue indirectly

hmenke commented 2 years ago

Oh, you misunderstand. I'm not going to fix anything in external. Unless someone else provides a fix this will remain open.

tobiasBora commented 2 years ago

Oh, so what's wrong with the fix you propose (beside it being not yet tested)?

u-fischer commented 1 year ago

The problem is not only related to erronous document. If you compile first a document correctly with --shell-escape, then change the figure and recompile without --shell-escape, then tikz will neither complain that the run didn't work, nor that the figure changed, and the third compilation will actually claim ===== Image 'tikz-min-figure0' is up-to-date. ======, even if you activate --shell-escape again.