Série: English
python
96 linhas
· Atualizado 2026-08-02
build_chapters.py
English/English Grammar/build_chapters.py
#!/usr/bin/env python3
"""Build a standalone, fully styled PDF for every chapter/appendix file.
Each chapter fragment in chapters/ is wrapped in a small driver document
that loads the shared preamble, sets the correct chapter number, and pulls
cross-reference targets from main.aux (via xr-hyper) so references to other
chapters resolve to the numbers used in the full book.
Output: one PDF per chapter in pdfs/, e.g. pdfs/ch01-nouns-articles.pdf
"""
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent
CHAPTERS = ROOT / "chapters"
BUILD = ROOT / "build"
OUT = ROOT / "pdfs"
TITLES = {
"preface": "How to Use This Book",
}
# Appendix letter -> chapter counter value before the \chapter command
APPENDICES = {
"app-irregular-verbs": 0, # Appendix A
"app-glossary": 1, # Appendix B
"app-answer-key": 2, # Appendix C
}
DRIVER = r"""\documentclass[11pt,twoside,openany]{book}
\usepackage{xr-hyper}
\input{preamble}
\externaldocument{main}
\hypersetup{pdftitle={English Grammar Course --- %(title)s}}
\begin{document}
%(setup)s
\input{chapters/%(name)s}
\end{document}
"""
def setup_for(name: str) -> str:
if name == "preface":
return ""
if name in APPENDICES:
return "\\appendix\n\\setcounter{chapter}{%d}" % APPENDICES[name]
m = re.match(r"ch(\d+)", name)
if m:
return "\\setcounter{chapter}{%d}" % (int(m.group(1)) - 1)
raise ValueError(f"Unrecognized chapter file: {name}")
def main() -> int:
BUILD.mkdir(exist_ok=True)
OUT.mkdir(exist_ok=True)
if not (ROOT / "main.aux").exists():
print("main.aux not found -- compile main.tex first", file=sys.stderr)
return 1
failures = []
files = sorted(CHAPTERS.glob("*.tex"))
for i, tex in enumerate(files, 1):
name = tex.stem
title = TITLES.get(name, name)
driver = BUILD / f"{name}.tex"
driver.write_text(
DRIVER % {"name": name, "setup": setup_for(name), "title": title}
)
print(f"[{i}/{len(files)}] {name} ...", flush=True)
res = subprocess.run(
[
"latexmk", "-pdf", "-interaction=nonstopmode",
f"-output-directory={BUILD}", str(driver),
],
cwd=ROOT, capture_output=True, text=True,
)
pdf = BUILD / f"{name}.pdf"
if res.returncode != 0 or not pdf.exists():
failures.append(name)
print(res.stdout[-2500:], file=sys.stderr)
continue
(OUT / f"{name}.pdf").write_bytes(pdf.read_bytes())
if failures:
print("FAILED:", ", ".join(failures), file=sys.stderr)
return 1
print(f"OK: {len(files)} PDFs written to {OUT}")
return 0
if __name__ == "__main__":
sys.exit(main())