for not-installed lookups too
Caught by local TL 2026 verification: 'tlmgr info --only-installed bogus-xyz'
prints
package: bogus-xyz
installed: No
so the previous grep '^package:' matched both installed and not-installed,
which would silently skip *every* collection — including fontsextra and
latexextra that genuinely need network install. The container build would
exit 0 with no install attempted and produce a :latest image still missing
newpx, recreating exactly the bug this branch is trying to fix.
Anchor on 'installed: Yes' (after the colon, allowing for whitespace) so
not-installed collections fall through to the install loop as intended.
The 16:23 container rebuild caught a real flaky failure with the previous
commit's stricter exit-non-zero behavior: collection-fontsrecommended
failed twice when tlmgr's mirror.ctan.org redirect landed on stale mirrors
(ctan.math.illinois then mirrors.mit). On a stale mirror tlmgr refuses
with a silent 'Remote database at <url>' / exit 1, never reaching the
'package already present' fast-path that would have succeeded against a
fresh mirror.
install-tl's scheme-medium already installs basic, fontsrecommended,
fontutils, latex, latexrecommended, luatex, pictures, plus most language
collections — 7 of the 9 entries in tl_packages. Only fontsextra and
latexextra genuinely need a tlmgr install operation. Query the local
tlpdb with 'tlmgr info --only-installed' (no network) and skip the
network call entirely when the collection is already present, sidestepping
the random-mirror staleness for the redundant entries.
Previously install-tl-collections.sh exited 0 even when collections in
tl_packages failed to install, so the Linux Docker image would tag and
publish as :latest with missing fonts/packages. The failure surfaced
hours later as a downstream PDF render error
('LaTeX Error: File `newpxtext.sty` not found') in book-build-container,
making the chain of causation hard to spot.
Every collection listed in tl_packages is required by the book PDF
build — there is no soft-dependency tier. If any of them cannot be
installed, exit non-zero so the container build fails fast and the
broken image is never published.
Also tighten the 'tlmgr not available' branch to fail rather than skip:
no tlmgr means no PDF build, so silently moving on is wrong.
The previous retry loop used 'if tlmgr install ...; then' which discarded
tlmgr's actual error output, leaving only '❌ Attempt N failed' in the CI
log. On the 2026-05-04 rebuild this masked the real reason
collection-fontsextra refused to install (the version-mismatch error fixed
in the previous commit) and made the failure invisible until a downstream
PDF build broke 3 hours later.
Capture tlmgr's combined stdout and stderr to a tmpfile, always emit it,
and report the exit code on failure so the diagnostic reaches the build
log on the first attempt.
When install-tl runs against a tlnet snapshot and minutes later the script
calls 'tlmgr install collection-fontsextra', tlnet has often rolled forward
and tlmgr refuses with "Local TL version is incompatible with the
repository", which on the 2026-05-04 rebuild left newpx (and the rest of
collection-fontsextra) absent from the published :latest image, producing
a Vol II PDF build failure for newpxtext.sty 3 hours later.
Run 'tlmgr update --self' once before the collection install loop so the
local tlmgr matches whatever revision the remote currently advertises.
Failure here is non-fatal so a flaky update doesn't block the build.
Default RUN /bin/sh doubles 82414 inside double quotes to the shell PID, so
command substitution with Docker escaped dollar-paren was mis-parsed
(Phase 10: syntax error on open paren). Use POSIX backticks for command
substitution, brace variables for echo, and a short file-header note.
fs configure requires libuv headers/pkg-config; without libuv1-dev the build
fails on fs then cascades to rmarkdown. Pre-flight: pkg-config --exists libuv.
- Add book/tools/dependencies/required_r_packages.R for a single source of truth
- install_packages.R: fail if any package not loadable after install; source shared list
- verify: match R_LIBS_USER and requireNamespace only (no re-source of full install/tinytex)
- Dockerfile: COPY and cleanup /tmp/required_r_packages.R with install/verify scripts
Phase 7 already runs install_packages.R and verify, then removes /tmp copies. The old steps 9.1–9.3 only re-ran a minimal fallback. Remove redundant R library RUN; renumber phases 12→11 and 13→12.
RUN is preprocessed: bare $collection/$i/$success etc. become empty. Double $ so dash sees the real loop variables. Same for package_count echo after assignment.
BuildKit can expand an inline PATH+= such that /usr/bin is lost (head, etc. missing). TeX step uses an explicit system PATH; drop redundant health-check exports; no tlmgr|head.
The sequence $$(( is parsed as one escaped $, leaving bash-style
(( which /bin/dash rejects (Syntax error: "(" unexpected). Use
$$$(( so the shell receives proper POSIX $$(( arithmetic
expansion.
Dockerfile treats $4, $PATH, $?, ${duration} in shell RUN as build-time; use $$ so the image script keeps correct dash/sh behavior. Bump TEXLIVE_INSTALLER_REVISION=6.
Dockerfile RUN must use $$( for literal $( and $$(( for $(( so dash sees command/arithmetic substitution. Fixes Step 5.5 (tlmgr collections) parse failure after TeX layer started building.
The multi-line RUN hit dash/buildx parsing issues (Syntax error: '(' unexpected). Move download + install-tl into /opt/install-texlive-base.sh and invoke with a short RUN; bump TEXLIVE_INSTALLER_REVISION to invalidate cache.
CI /bin/sh (dash) failed with 'Syntax error: ( unexpected' on the TeX layer.
Use cut -c12-15 for year (install-tl-YYYYMMDD), separate case arms for
2026/2027, and error lines without a single echo that could confuse the
parser. REVISION=4 to refresh build cache.
mirrors still serve install-tl-unx for TL2025 while main tlnet is 2026; a fixed
-repository caused local 2025 / repository 2026. After extract, derive year from
install-tl-YYYY* path, use Utah historic tlnet-final for 2025 and mirror.ctan
for 2026+, save URL for tlmgr, bump install revision.
Merge download/extract and profile/install into one RUN so buildx cannot cache
a stale install-tl-unx (wrong TL year) separately from -repository. Bump
TEXLIVE_INSTALLER_REVISION when forcing a fresh installer after CTAN rollover.
Historic TL2025 repo breaks when install-tl-unx is already TL2026 (local 2026 vs
repo 2025). Use main systems/texlive/tlnet with the same installer download.
CTAN main tlnet moved to 2026 while install-tl-unx still targets TL2025, so
install-tl failed immediately with local/repository year mismatch. Use Utah
historic tlnet-final and set tlmgr repository to match for collection installs.
- mkdir R_LIBS_USER before Rscript; set .libPaths + cloud.r-project.org in install_packages.R
- Pre-flight step fails in seconds if cmake or pkg-config missing (avoids 30–60m then fs/rmarkdown/tidyverse verify failure)
- Ncpus=1 for R package compiles; realistic time hint for the long CRAN compile step
R package 'fs' (transitive dep of tidyverse/rmarkdown/sass/bslib) bumped to
1.6.x in CRAN. The new version bundles libuv-v1.52.0 source and requires
cmake to build it. The Linux container apt install list had neither cmake
nor pkg-config, so every clean rebuild failed at:
/bin/bash: line 2: cmake: command not found
make: *** [Makevars:44: libuv] Error 127
ERROR: compilation failed for package 'fs'
The 'fs' failure cascaded into sass, gargle, bslib, rmarkdown, tidyverse,
googledrive, googlesheets4, reprex -- causing verify_r_packages.R to fail
on 'rmarkdown, tidyverse' and aborting the weekly container rebuild.
Adds cmake and pkg-config to the Phase 2 apt install list. Restores the
ability to build R source packages that vendor C/C++ libraries.
- Sync translated READMEs (ja, ko, zh) with renamed workflow files and
add Slides, Instructors, StaffML badges
- Fix Docker Windows README paths and workflow reference
- Rewrite book/tools/scripts README to point to Binder CLI first
- Update kits badge from kits-publish to kits-validate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Windows container build was failing with "not enough space on the disk"
during TeX Live font installation. This adds runner-level disk cleanup before
the build, TeX Live doc/source/backup removal within the same Docker layer,
and Scoop/Chocolatey/pip cache purging in the Dockerfile cleanup phase.
Use cderv/r-bucket Scoop bucket to install a version-pinned Quarto,
ensuring llms-txt support on Windows. Replaces the extras/quarto
install which lagged behind the required version.
Resolves#1213.
Restore Windows container build support that was accidentally removed
in commits a76aab467..a90c8803f. This restores:
- Windows Docker infrastructure (book/docker/windows/)
- Windows container build workflow (infra-container-windows.yml)
- Windows matrix entries in book-build-container.yml
- Windows health check support in infra-health-check.yml
- Windows build flags in book-validate-dev.yml and book-publish-live.yml
Restored from pre-removal state at f85e319d6.
Per request, removed all traces of Windows container builds from the project.
This simplifies the CI pipeline to be Linux-only.
- Deleted `book/docker/windows/` directory and its Dockerfile
- Deleted `.github/workflows/infra-container-windows.yml`
- Removed Windows matrix jobs and steps from `book-build-container.yml`
- Removed Windows inputs and outputs from `book-build-container.yml`
- Removed Windows health checks from `infra-health-check.yml`
- Removed Windows references from `book-publish-live.yml`
- Removed Windows references from `book-validate-dev.yml`
Use single-quoted python -c code in the Docker RUN command so the command parses correctly under pwsh -Command and avoids parser errors during image build.
Preserve container PATH during Windows docker-run steps and create/verify a python3 alias from Scoop Python so Quarto/Jupyter kernels that invoke python3 work reliably in both install-time and final verification checks.
Update Dockerfile and workflow final verification steps to normalize native command exit detection and fail explicitly on non-zero exits, avoiding false positives and false negatives in PowerShell checks.
Avoid checking $LASTEXITCODE after a piped lualatex command by capturing command output first and normalizing exit-code detection, preventing false non-zero failures.
Keep fail-fast installation checks for Ghostscript command presence, but defer executing Ghostscript until the final verification phase where full runtime dependencies and PATH are in place.
Verify Ghostscript through the Scoop shim (`gs`) and restore the Ghostscript `lib` path in image PATH so DLL-dependent checks pass during install and final verification.
Add immediate per-tool post-install checks with explicit command resolution and exit handling, keep end-of-job final verification with isolated per-tool reporting, and ensure rsvg-convert is installed/verified for Quarto PDF SVG conversion.
- Add explicit ENV PATH directive (Phase 15) so Docker layers
inherit tool paths instead of relying on registry writes
- Reorder phases: TeX Live moved last (slowest, fail last)
- Create stable symlink C:\texlive\bin\windows for year-agnostic PATH
- Skip pip self-upgrade to avoid WinError 3 shim lock
- Use gswin64c (correct Scoop binary name) instead of gs
- Add rsvg-convert fallback to Chocolatey if Scoop fails
- Replace fragile verification loop with Test-Tool function
- Relax ErrorActionPreference for Chocolatey TeX Live in baremetal
Add fallback search for tlmgr.bat when year-directory pattern
fails, validate bin directory exists before use, and verify
lualatex.exe path explicitly. Adds diagnostic output to help
debug future path resolution issues.
Replace double-quoted string interpolation in throw statement
with -f format operator to prevent Docker RUN flattening from
stripping quotes and causing PowerShell parse errors.
- Baremetal workflow: verification step now tracks failures and exits
non-zero when tools are missing (previously always reported success)
- Baremetal workflow: R.exe --version replaced with Rscript --version
to avoid PowerShell Invoke-History alias collision
- Windows Dockerfile: Quarto install switched from direct zip download
(C:\quarto-1.9.27\bin) to scoop install extras/quarto for consistent
PATH handling via Scoop shims
- Windows Dockerfile: final verification rewritten with failure tracking
and exit 1 on missing tools
Adds rsvg-convert to the Windows Dockerfile to enable SVG-to-PDF conversion for Quarto, including its verification.
Refactors Quarto document source:
- Renames a speculative decoding footnote for improved clarity.
- Standardizes an internal TikZ drawing macro boolean flag from `\ifbox@dashed` to `\ifboxdashed` across several files.
Quarto's Lua filter calls rsvg-convert to convert SVG figures to PDF
during PDF builds. librsvg2-dev was present (C headers/lib) but the
binary package librsvg2-bin was missing, causing a FATAL build error:
'Could not convert a SVG to a PDF. Please ensure rsvg-convert is on path'
Also adds rsvg-convert to the Phase 2 verification checks so missing
tools are caught at image build time, not at render time.
Move the ~100-line Phase 4 inline PowerShell block into
book/docker/windows/install_texlive.ps1. The Dockerfile now simply
COPYs and calls the script. Benefits:
- Script can be tested and updated independently of the Dockerfile
- Cleaner, readable PS syntax (no backtick line-continuation noise)
- Docker layer only invalidates when the script actually changes
CI pins black==24.10.0 but requirements.txt had black>=23.0.0, causing
pre-commit to reformat 11 QMD files on the CI run and fail. Format all
affected files locally with 24.10.0 to match CI expectations.
Also fix PowerShell PATH string interpolation in Windows Dockerfile:
use explicit concatenation instead of nested method call inside a
double-quoted string, which can be unreliable in some PS contexts.
Chocolatey's texlive wrapper sets ErrorActionPreference=Stop and relies on
install-tl picking a random CTAN mirror at runtime. When that mirror is
flaky (as mirrors.rit.edu was), the entire build fails with no fallback.
Switch to calling install-tl-windows.bat directly:
- Set ErrorActionPreference=Continue so we own error handling
- Write a profile with instopt_adjustrepo=0 to prevent auto-mirror switching
- Pass -repository explicitly, trying Illinois → MIT → mirror.ctan.org in order
- Pin tlmgr repository post-install to the same stable mirror
- Remove Chocolatey texlive dependency entirely