Files
Vijay Janapa Reddi 38439425a6 Move all book sources under books/ and retire the duplicate tree
The repository carried the book twice. publishing/quarto/contents/vol{1..4}/
was what every build and every check read; books/vol{1..4}/ was a second
tracked copy that fed nothing and had drifted badly, holding 3 vol3 chapters
against 30 in the live tree. A `book` symlink pointed at publishing/, so
book/quarto/ and publishing/quarto/ were one directory under two names, next
to a books/ that was a third thing. Editorial work kept landing in the copy
nothing rendered.

books/ is now the Quarto project root and the only place book sources live:

  books/vol1..vol4          one directory per volume
  books/shared/             frontmatter, backmatter, _partials, assets, tex,
                            filters, scripts, audits, publish, calc
  books/config/             the per-volume quarto configs
  books/_extensions/        Quarto needs these at the project root
  books/index-vol{1..4}.qmd, references*.bib, _variables.yml, 404.qmd
  books/_build/             render output, gitignored and disposable

The toolchain stays in publishing/ and is now unambiguous, since it no longer
contains any of the book. The `book` symlink is gone and the CLI is reached as
./binder from the repository root; publishing/binder resolves through the
symlink so invoking it from either place works.

Config paths are relative to the project root, so a chapter entry goes from
contents/vol1/introduction/introduction.qmd to vol1/introduction/introduction.qmd,
and shared material picks up a shared/ prefix. 5,204 path references were
rewritten across 401 files, plus 127 segment-built paths in Python that string
matching could not see, plus 795 ./book/binder references.

Verified rather than assumed: a single-chapter HTML render produces output
equivalent to the same build on dev, 432,901 bytes against 433,158, the same
18 images, zero unresolved cross-references on both. Scoped checks return
identical findings on both trees.

One behaviour genuinely changes. While the sources sat under contents/, the
checks resolved their default scan root to the Quarto project directory rather
than the content directory, so a bare `./binder check tables` matched no files
and always reported success. Now that the project root and the content root
are the same directory the default works, and it immediately surfaces 31
pre-existing findings in vol3 and vol4 that were always present and never
reported. Those are content issues to fix separately, not regressions from
this move.

docs/REPO_LAYOUT.md describes the result. docs/BOOKS_MIRROR_RETIREMENT.md
records what the retired mirror held, which commits landed only there, and how
to recover any of it from history.
2026-09-10 13:12:19 +02:00

51 lines
1.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Fix inline math for dimension-like N×M only (two numbers) in QMD files.
When a digit is adjacent to $ (e.g. 224$\\times$224), some Quarto/Pandoc
configurations fail to open math mode. Wrapping the full expression in one
math span (e.g. $224\\times224$) fixes rendering. Only dimension patterns
(two numbers) are fixed here; multiplier "N×" is left as N$\\times$ per
LaTeX/typography convention (number in text, symbol in math).
"""
from __future__ import annotations
import re
from pathlib import Path
def fix_times_math(text: str) -> str:
# Malformed dimension: $N\times$ M (space before second number) -> $N\times M$
text = re.sub(
r"[\$](\d[\d,.]*)[\\]times[\$] +(\d[\d,.]*)",
r"$\g<1>\\times\g<2>$",
text,
)
# Two numbers: 4096$\times$4096 -> $4096\times4096$
text = re.sub(
r"(\d[\d,.]*)[\$][\\]times[\$](\d[\d,.]*)",
r"$\1\\times\2$",
text,
)
return text
def main() -> None:
root = Path(__file__).resolve().parent.parent / "contents"
if not root.is_dir():
raise SystemExit(f"Contents root not found: {root}")
qmd_files = list(root.rglob("*.qmd"))
total_replacements = 0
for path in sorted(qmd_files):
content = path.read_text(encoding="utf-8")
new_content = fix_times_math(content)
if new_content != content:
path.write_text(new_content, encoding="utf-8")
total_replacements += 1
print(path.relative_to(root.parent))
print(f"Updated {total_replacements} files.")
if __name__ == "__main__":
main()