Skip to content

Latest commit

 

History

History
193 lines (159 loc) · 9.42 KB

File metadata and controls

193 lines (159 loc) · 9.42 KB

larafly by example — the book build system

This directory builds larafly by example, a bilingual (EN + ES) book teaching LaraFly by walking through the samples/lumen project chapter by chapter. It mirrors fireflyframework-pyfly/book/'s architecture (WeasyPrint -> PDF, a hand-rolled EPUB3 assembler, python-markdown with custom directives), renamed and re-tokened for LaraFly/PHP/Laravel.

This is a Python toolchain, isolated from the PHP monorepo: book/.venv/ and book/dist/ (the generated PDF/EPUB) are gitignored and never committed. Only the sources — book.yaml, build/*.py, theme/*.css, art/, src/ (EN), src-es/ (ES), tests/ — are tracked.

Published PDF and EPUB editions (English + Español) are rebuilt with the MkDocs site after every successful main CI run. GitHub releases also carry the books built from their tag. Each download set includes SHA256SUMS and a build-info.json source commit.

One-time setup

The first build needs network access (to install the Python deps) and a native cairo + pango stack (WeasyPrint's rendering backend). Every build after that is fully offline.

# 1. Create the venv (Python 3.12 preferred; this repo used 3.13 — 3.12 was not
#    installed on the build machine, and WeasyPrint has no 3.12-specific pin).
python3.12 -m venv book/.venv   # or: python3.13 -m venv book/.venv
book/.venv/bin/pip install -r book/build/requirements.txt

# 2. macOS only: WeasyPrint links against cairo/pango via ctypes at runtime.
brew install cairo pango

book/build/run.sh sets DYLD_FALLBACK_LIBRARY_PATH to Homebrew's lib/ so WeasyPrint finds libcairo/libpango without any manual export. On Linux, install the equivalent packages (e.g. apt install libcairo2 libpango-1.0-0 libpangoft2-1.0-0) and run.sh's DYLD_FALLBACK_LIBRARY_PATH export is a no-op (Linux uses the system loader path instead).

Building the book

bash book/build/run.sh                        # English  -> book/dist/larafly-by-example.{pdf,epub}
bash book/build/run.sh --config book.es.yaml  # Spanish  -> book/dist/larafly-by-example-es.{pdf,epub}

book/dist/ is created on demand and is gitignored — nobody commits a generated PDF/EPUB.

To run the same pipeline as CI, including the book tests, PHP listing checks, both editions, the PDF text-boundary check, the strict MkDocs build and site/downloads/ packaging:

bash scripts/build-docs.sh

Verifying PHP code listings

A fenced ```php block is linted with the real PHP CLI (php -l, via a temp file — no execution) unless it carries a <!-- source: … --> marker. A marked block is a verbatim excerpt of the repository file it names — a fragment that does not parse on its own — and is checked by line-for-line comparison in DocsCodeIsRealTest instead. Every listing in src/ and in src-es/ carries one marker or the other, and both directories are named in DocsCodeAudit::AUDITED, so every marked block in either edition is held to the comparison:

book/.venv/bin/python book/build/verify_code.py book/src --require-provenance
book/.venv/bin/python book/build/verify_code.py book/src-es --require-provenance

Exits non-zero and prints FAIL <file>:<line> ... for any listing that fails to parse, and — with --require-provenance — for any php listing carrying neither marker.

Running the pipeline's own tests

cd book && ../book/.venv/bin/python -m pytest -q

Covers the Markdown extension (::: figure, ::: listing, admonitions), the EPUB3/OCF assembler, and the PHP-listing extractor/linter.

Layout

book/
  book.yaml          # EN manifest: title/author/rights, front matter, parts/chapters
  book.es.yaml        # ES manifest (manuscript_dir: src-es)
  build/
    build.py          # orchestrates: manifest -> items -> EpubBuilder + render_pdf
    md.py             # Markdown -> XHTML: ::: figure / ::: listing directives,
                       #   note/tip/warning/laravel admonitions, codehilite
    epub.py            # stdlib-only EPUB3 (OCF) zip assembler
    pdf.py             # WeasyPrint HTML -> PDF
    gen_cover.py        # validates canonical art; --render rasterizes outlined SVGs
    verify_code.py      # fenced ```php listings: `php -l`, except `source:` ones
    run.sh              # sets DYLD_FALLBACK_LIBRARY_PATH, execs build.py
    requirements.txt     # pinned: weasyprint, markdown, pygments, pyyaml, pytest, cairosvg
  theme/
    tokens.css           # CSS custom properties (palette)
    book.css             # shared screen/EPUB styles
    print.css             # @page rules, running heads, page-break control (PDF only)
    pygments.css           # syntax-highlighting token colors
  art/
    cover{,-es}.{svg,png}       # canonical localized front covers
    back-cover{,-es}.{svg,png}  # canonical localized back covers
    PROVENANCE.md              # source and delivered artwork hashes
    figures/                 # inline-SVG diagrams referenced by ::: figure
    openers/                  # reserved for future per-chapter opener art (empty)
  src/                         # EN manuscript (Markdown)
    00-front/                   # title/copyright/dedication/preface/conventions
    00-quickstart.md             # "Build Lumen step by step" quick start
    01..13a-*.md                 # the sixteen chapters, 4A, 10A and 13A included (Parts I-IV)
    90-appendix-a-laravel.md      # Laravel -> LaraFly cheat-sheet
    94-glossary.md                # glossary
  src-es/                        # ES manuscript, same structure/filenames
  tests/
    test_md.py, test_epub.py, test_verify_code.py

Markdown conventions

  • Code listings: real chapters use a plain fenced block with the language tag php, e.g. ```php. These are both syntax-highlighted (via Pygments) and linted by verify_code.py. A custom ::: listing <label> | <caption> block directive is also available (ported from PyFly) for listings that need a file-name tab and a numbered caption baked into the HTML.
  • Figures: ::: figure <path.svg> | <caption> inlines an SVG (or embeds a raster image as a data URI) so it renders crisply in both the EPUB and the print PDF.
  • Callouts: !!! note, !!! tip, !!! warning (admonition extension), and LaraFly's own !!! laravel "..." — a Laravel-parity callout that maps a LaraFly concept directly to its native Laravel equivalent (this replaces PyFly's !!! spring callout).

Manuscript status

The manuscript is structurally complete in both languages: a five-file front matter, a "Build Lumen step by step" quick start, sixteen chapters across four parts —

  • Part I — Foundations: Why LaraFly, Dependency Injection & Auto-Configuration, Configuration/Profiles/Secrets, Your First HTTP API
  • Part II — Modelling & Persisting the Domain: Persistence & Repositories, Domain-Driven Design
  • Part III — Coordinating & Securing the Application: CQRS, Event-Driven Architecture & the Transactional Outbox, Transactions & the #[Transactional] proxy, Security, OAuth2 and OpenID Connect
  • Part IV — Observability, Testing & Delivery: Observability/Actuator, Testing, the CLI & the Zero-Reflection Cache, Feature Flags

— plus Appendix A (Laravel → LaraFly cheat-sheet) and a Glossary. Every chapter walks the real samples/lumen project. Every fenced ```php listing in src/ and in src-es/ carries either a source: marker naming the repository file it was excerpted from — compared line for line by the repository's own documentation guard — or an illustrative: marker saying it is the reader's own code, which is the kind php -l checks. Both editions build to book/dist/ as PDF + EPUB.

The two editions are the same book, line for line. Every chapter file has the same sections in the same order at the same line numbers, and every php listing and every source:-marked excerpt in the Spanish edition is the English one character for character — identifiers, config keys, endpoint paths and HTTP transcripts are never translated. What a Spanish fence does translate is the trailing comment on a shell or tree listing: that is prose the reader reads, not code they run, and no php or source: block carries one. The repository's own prose guard derives both halves of that parity — the per-chapter sizes, and the blocks themselves, byte for byte — and fails the build the moment one edition stops matching the other.

Branded front and back covers

The English and Spanish manifests select their own front/back SVG and PNG files under art/. See artwork provenance for the canonical brand kit source and delivered asset hashes. The SVG typography is outlined; the build needs no author-machine fonts for the covers.

book/.venv/bin/python book/build/gen_cover.py

This validates all four SVG/PNG pairs without modifying them. Use an explicit --render only to rasterize the checked-in SVGs again. The book build fails if a configured PNG is missing. Covers fill the PDF trim without running text; EPUB editions include accessible front/back documents and localized navigation.

Book-only editions can be published separately under books-* tags and must not be marked as the latest framework release. Keep the book source commit and asset checksums with the edition. A book-only edition does not change framework package versions or replace the assets attached to an existing framework version.