mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-11-09 10:39:41 -06:00
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.
51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
#!/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()
|