Skip to content

Commit f22ebc5

Browse files
committed
Script: refactor LaTeX multi-pass compilation (PR #2834)
1 parent 2f35fe3 commit f22ebc5

1 file changed

Lines changed: 27 additions & 36 deletions

File tree

pretext/lib/pretext.py

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -688,27 +688,7 @@ def individual_latex_image_conversion(latex_image, outformat, dest_dir, method):
688688
log.debug("tex executable: {}".format(tex_executable_cmd[0]))
689689
latex_cmd = tex_executable_cmd + ["-interaction=nonstopmode", "-halt-on-error", latex_image]
690690
log.info("converting {} to {}".format(latex_image, latex_image_pdf))
691-
# Run LaTeX on the image file, usual console transcript is stdout.
692-
# "result" is a "CompletedProcess" object. Specifying an encoding
693-
# causes captured output to be a string, which is convenient.
694-
result = subprocess.run(latex_cmd, stdout=subprocess.PIPE, encoding="utf-8")
695-
696-
# It may be that the image needs to be compiled twice. If the .log file contains
697-
# the string `Rerun to get`, then the document should be compiled again.
698-
699-
# We keep track of how many times we've tried to compile the document and
700-
# bail if it looks like we're stuck in a loop.
701-
loop_count = 0
702-
MAX_LOOPS = 10
703-
while result.returncode == 0 and "Rerun to get" in open(latex_image_log).read() and loop_count < MAX_LOOPS:
704-
msg = "File {} needs to be processed with LaTeX again. Rerunning LaTeX for pass number {}."
705-
log.info(msg.format(latex_image, loop_count + 2))
706-
result = subprocess.run(latex_cmd, stdout=subprocess.PIPE, encoding="utf-8")
707-
loop_count += 1
708-
709-
if loop_count == MAX_LOOPS:
710-
log.error("Detected infinite loop while compiling {}. Aborting.".format(latex_image))
711-
result.returncode = 1
691+
result = _latex_compile(latex_cmd, latex_image_log, latex_image, capture_output=True)
712692

713693
if result.returncode != 0:
714694
# failed to compile the LaTeX image
@@ -5154,6 +5134,31 @@ def latex(xml, pub_file, stringparams, extra_xsl, out_file, dest_dir):
51545134
###################
51555135

51565136

5137+
def _latex_compile(latex_cmd, log_file, source_name, max_passes=10, capture_output=False):
5138+
"""Compile a LaTeX file, rerunning until cross-references settle.
5139+
5140+
Runs the initial pass, then reruns while the log file requests
5141+
"Rerun to get" and the pass limit has not been reached.
5142+
5143+
Returns the CompletedProcess from the final pass. Sets returncode
5144+
to 1 if the pass limit is reached without convergence.
5145+
"""
5146+
run_kwargs = {"stdout": subprocess.PIPE, "encoding": "utf-8"} if capture_output else {}
5147+
result = subprocess.run(latex_cmd, **run_kwargs)
5148+
pass_count = 1
5149+
while (result.returncode == 0
5150+
and os.path.isfile(log_file)
5151+
and "Rerun to get" in open(log_file).read()
5152+
and pass_count < max_passes):
5153+
log.info("Rerunning LaTeX for {} (pass {})".format(source_name, pass_count + 1))
5154+
result = subprocess.run(latex_cmd, **run_kwargs)
5155+
pass_count += 1
5156+
if pass_count == max_passes and result.returncode == 0:
5157+
log.warning("LaTeX compilation of {} required {} passes and may not have converged.".format(source_name, max_passes))
5158+
result.returncode = 1
5159+
return result
5160+
5161+
51575162
def pdf(xml, pub_file, stringparams, extra_xsl, out_file, dest_dir, method, outputs):
51585163
"""
51595164
Generate a PDF from an XML source using LaTeX as an intermediate format.
@@ -5237,21 +5242,7 @@ def pdf(xml, pub_file, stringparams, extra_xsl, out_file, dest_dir, method, outp
52375242
# matching the strategy used for standalone latex-image compilation.
52385243
latex_cmd = latex_exec_cmd + ["-halt-on-error", sourcename]
52395244
logname = basename + ".log"
5240-
MAX_PASSES = 10
5241-
result = subprocess.run(latex_cmd)
5242-
for _ in range(2, MAX_PASSES + 1):
5243-
result = subprocess.run(latex_cmd)
5244-
if result.returncode != 0:
5245-
break
5246-
if os.path.isfile(logname):
5247-
with open(logname) as f:
5248-
log_contents = f.read()
5249-
if "Rerun to get" not in log_contents:
5250-
break
5251-
else:
5252-
break
5253-
else:
5254-
log.warning("LaTeX compilation of {} required {} passes and may not have converged.".format(sourcename, MAX_PASSES))
5245+
result = _latex_compile(latex_cmd, logname, sourcename)
52555246

52565247
# If we want all outputs, we copy the entire build directory now that the PDF is built
52575248
# so we can get the *.log, *.aux, etc build files.

0 commit comments

Comments
 (0)