diff --git a/news/changelog-1.4.md b/news/changelog-1.4.md index e2530df14e..db43c3cad5 100644 --- a/news/changelog-1.4.md +++ b/news/changelog-1.4.md @@ -251,3 +251,4 @@ - ([#7032](https://github.com/quarto-dev/quarto-cli/issues/7032)): `quarto` is now correctly working when installed in a folder with spaces in path. - ([#7131](https://github.com/quarto-dev/quarto-cli/issues/7131)): Fix typo in ISBN entry for JATS subarticle template (author: @jasonaris). - ([#3599](https://github.com/quarto-dev/quarto-cli/issues/3599), [#5870](https://github.com/quarto-dev/quarto-cli/issues/5870)): Fix hash issue causing unexpected render when `freeze` is activated on Windows but re-rendered on Linux (e.g. in Github Action). +- ([#7252](https://github.com/quarto-dev/quarto-cli/issues/7252)): Improve handling with `tlmgr` of some mismatched LaTeX support files, associated with `expl3.sty` loading. diff --git a/src/command/render/latexmk/parse-error.ts b/src/command/render/latexmk/parse-error.ts index 65717313f2..16245a50a0 100644 --- a/src/command/render/latexmk/parse-error.ts +++ b/src/command/render/latexmk/parse-error.ts @@ -230,7 +230,7 @@ const packageMatchers = [ return "lua-uni-algos.lua"; }, }, - + { regex: /.* Loading '([^']+)' aborted!.*/g }, { regex: /.*! LaTeX Error: File `([^']+)' not found.*/g }, { regex: /.* file ['`]?([^' ]+)'? not found.*/g }, { regex: /.*the language definition file ([^ ]+) .*/g }, diff --git a/src/command/render/latexmk/pdf.ts b/src/command/render/latexmk/pdf.ts index d1a55389dc..8756caec09 100644 --- a/src/command/render/latexmk/pdf.ts +++ b/src/command/render/latexmk/pdf.ts @@ -156,7 +156,6 @@ async function initialCompileLatex( quiet?: boolean, ) { let packagesUpdated = false; - let tlmgrUpdated = false; while (true) { // Run the pdf engine const response = await runPdfEngine( @@ -197,7 +196,6 @@ async function initialCompileLatex( logProgress("updating tlmgr"); } await pkgMgr.updatePackages(false, true); - tlmgrUpdated = true; info(""); if (!quiet) { @@ -208,23 +206,6 @@ async function initialCompileLatex( } const logText = Deno.readTextFileSync(response.log); - // See if tlmgr just needs to be updated - // https://github.com/rstudio/tinytex/commit/5946a2a1bf3c6ecefbd1213178a4e473ff4c26dc - // https://github.com/quarto-dev/quarto-cli/issues/7087 - if (logText.match(/.* Loading '([^']+)' aborted!/)) { - if (!tlmgrUpdated) { - continue; - } else { - // We've already tried updating, just need to throw and die - // We failed to install packages (but there are missing packages), give up - displayError( - "tlmgr needs to be updated, but the update failed", - response.log, - response.result, - ); - return Promise.reject(); - } - } // Try to find and install packages const packagesInstalled = await findAndInstallPackages( diff --git a/src/command/render/latexmk/texlive.ts b/src/command/render/latexmk/texlive.ts index 1033ad8003..41468d1a67 100644 --- a/src/command/render/latexmk/texlive.ts +++ b/src/command/render/latexmk/texlive.ts @@ -225,6 +225,28 @@ async function installPackage( opts?: string[], quiet?: boolean, ) { + // if any packages have been installed already, update packages first + let isInstalled = await verifyPackageInstalled(pkg, context); + if (isInstalled) { + // update tlmgr itself + const updateResult = await updatePackages( + true, + true, + context, + opts, + quiet, + ); + if (updateResult.code !== 0) { + return Promise.reject(); + } + + // Rebuild format tree + const fmtutilResult = await fmtutilCommand(context); + if (fmtutilResult.code !== 0) { + return Promise.reject(); + } + } + // Run the install command let installResult = await tlmgrCommand( "install", @@ -240,8 +262,8 @@ async function installPackage( ); } - // Check whether we should update and retry the install - const isInstalled = await verifyPackageInstalled(pkg, context); + // Check whether we should update again and retry the install + isInstalled = await verifyPackageInstalled(pkg, context); if (!isInstalled) { // update tlmgr itself const updateResult = await updatePackages( @@ -255,6 +277,12 @@ async function installPackage( return Promise.reject(); } + // Rebuild format tree + const fmtutilResult = await fmtutilCommand(context); + if (fmtutilResult.code !== 0) { + return Promise.reject(); + } + // Rerun the install command installResult = await tlmgrCommand( "install", @@ -417,3 +445,16 @@ function tlmgrCommand( return execTlmgr([tlmgr.fullPath, tlmgrCmd, ...args]); } } + +// Execute fmtutil +// https://tug.org/texlive/doc/fmtutil.html +function fmtutilCommand(context: TexLiveContext) { + const fmtutil = texLiveCmd("fmtutil-sys", context); + return execProcess( + { + cmd: [fmtutil.fullPath, "--all"], + stdout: "piped", + stderr: "piped", + }, + ); +} diff --git a/tests/test.ts b/tests/test.ts index 2e3a3a0516..88117ffa42 100644 --- a/tests/test.ts +++ b/tests/test.ts @@ -74,7 +74,7 @@ export function testQuartoCmd( name, execute: async () => { const timeout = new Promise((_resolve, reject) => { - setTimeout(reject, 300000, "timed out after 5 minutes"); + setTimeout(reject, 600000, "timed out after 10 minutes"); }); await Promise.race([ quarto([cmd, ...args], undefined, context?.env), diff --git a/tests/unit/latexmk/expl3-aborted.log b/tests/unit/latexmk/expl3-aborted.log new file mode 100644 index 0000000000..7c01862d09 --- /dev/null +++ b/tests/unit/latexmk/expl3-aborted.log @@ -0,0 +1,17 @@ + + +Other content before + +compilation failed- tlmgr needs to be updated, but the update failed + + + LaTeX Error: Mismatched LaTeX support files detected. + (LaTeX) Loading 'expl3.sty' aborted! + (LaTeX) + (LaTeX) The L3 programming layer in the LaTeX format + (LaTeX) is dated 2023-08-29, but in your TeX tree the files require + (LaTeX) at least 2023-10-10. + + For immediate help type H . + +Other content after \ No newline at end of file diff --git a/tests/unit/latexmk/parse-error.test.ts b/tests/unit/latexmk/parse-error.test.ts new file mode 100644 index 0000000000..0526f6cadd --- /dev/null +++ b/tests/unit/latexmk/parse-error.test.ts @@ -0,0 +1,17 @@ +/* +* parse-error.test.ts +* +* Copyright (C) 2023 Posit Software, PBC +* +*/ + +import { findMissingFontsAndPackages } from "../../../src/command/render/latexmk/parse-error.ts" +import { unitTest } from "../../test.ts"; +import { assert } from "testing/asserts.ts"; + +unitTest("findMissingPackages", async () => { + const logText = Deno.readTextFileSync("expl3-aborted.log") + assert(findMissingFontsAndPackages(logText, ".")[0] === "expl3.sty" ); +}, { + cwd: () => "unit/latexmk/" +}); diff --git a/tests/utils.ts b/tests/utils.ts index 1c1cc6e6f7..55f2abd397 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -7,8 +7,6 @@ import { basename, dirname, extname, join } from "path/mod.ts"; import { parseFormatString } from "../src/core/pandoc/pandoc-formats.ts"; -import { quartoRules } from "../src/format/html/format-html-shared.ts"; -import { quarto } from "../src/quarto.ts"; import { kMetadataFormat, kOutputExt } from "../src/config/constants.ts"; // caller is responsible for cleanup!