# epub-stream justfile
# Host target used for local simulator/CLI binaries.
host_target := `if [ -n "${HOST_TEST_TARGET:-}" ]; then \
echo "$HOST_TEST_TARGET"; \
else \
rustc -vV | awk '/^host: / { print $2 }'; \
fi`
# Format code
fmt:
cargo fmt --all
# Check formatting without changes
fmt-check:
cargo fmt --all -- --check
# Type-check (default dev target matrix).
check:
cargo check --workspace --all-features
# Lint with clippy (single strict pass).
lint:
cargo clippy --workspace --all-features -- -D warnings
# Unit tests (fast default loop).
test:
cargo test --workspace --all-features --lib --bins
# Default developer loop: auto-format + check + lint + unit tests.
all:
just fmt
just check
just lint
just test
# CI add-on: run integration tests after baseline all.
ci:
just all
just test-integration
# Backward-compatible aliases.
strict:
just all
harden:
just all
# Integration tests (slower / broader; useful in CI).
test-integration:
cargo test --workspace --all-features --tests
# Strict memory-focused linting for constrained targets.
#
# - no_std pass: enforce core/alloc import discipline.
# - render pass: ban convenience constructors that hide allocation intent.
lint-memory:
just lint-memory-no-std
just lint-memory-render
# no_std/alloc discipline checks (core path only).
lint-memory-no-std:
cargo clippy --no-default-features --lib -- -D warnings -W clippy::alloc_instead_of_core -W clippy::std_instead_of_alloc -W clippy::std_instead_of_core
# Render crate allocation-intent checks.
lint-memory-render:
cargo clippy -p epub-stream-render --lib --no-deps -- -D warnings -W clippy::disallowed_methods
# Check split render crates
render-check:
cargo check -p epub-stream-render -p epub-stream-embedded-graphics -p epub-stream-render-web
# Lint split render crates
render-lint:
cargo clippy -p epub-stream-render -p epub-stream-embedded-graphics -p epub-stream-render-web --all-targets -- -D warnings -A clippy::disallowed_methods
# Test split render crates
render-test:
cargo test -p epub-stream-render -p epub-stream-embedded-graphics -p epub-stream-render-web
# Run all split render crate checks
render-all:
just render-check
just render-lint
just render-test
# Check no_std (no default features)
check-no-std:
cargo check --no-default-features
# Run ignored tests
test-ignored:
cargo test --all-features -- --ignored
# Run tests with output
test-verbose:
cargo test --all-features -- --nocapture
# Run allocation count tests
test-alloc:
cargo test --all-features --test allocation_tests -- --ignored --nocapture --test-threads=1
# Run embedded-focused suites (tiny budgets + reflow regression matrix).
test-embedded:
cargo test --all-features --test embedded_mode_tests -- --ignored --nocapture
cargo test -p epub-stream-embedded-graphics --test embedded_reflow_regression -- --nocapture
# Verify benchmark fixture corpus integrity
bench-fixtures-check:
sha256sum -c tests/fixtures/bench/SHA256SUMS
# Build docs
doc:
cargo doc --all-features --no-deps
# Build docs and fail on warnings
doc-check:
RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps
# Build docs and open locally
doc-open:
cargo doc --all-features --no-deps --open
# Build release
build:
cargo build --release --all-features
# Check CLI build
cli-check:
cargo check --features cli --bin epub-stream
# Run CLI
cli *args:
cargo run --features cli --bin epub-stream -- {{args}}
# Render EPUB pages to PNG snapshots for local visual layout debugging.
#
# Usage:
# just visualize
# just visualize tests/fixtures/bench/pg84-frankenstein.epub 5 0 12 target/visualize-default
visualize epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" start="0" pages="12" out="target/visualize-default" cover_page_mode="contain":
RUSTC_WRAPPER= cargo run -p epub-stream-embedded-graphics --bin visualize --target {{ host_target }} -- \
{{epub}} \
--chapter {{chapter}} \
--start-page {{start}} \
--pages {{pages}} \
--out {{out}} \
--cover-page-mode {{cover_page_mode}}
# Launch interactive web preview with live re-render API.
# Exposes primary typography + cover policy controls for quick e-reader tuning.
web-preview epub="tests/fixtures/bench/pg84-frankenstein.epub" port="42817" justify_mode="adaptive-inter-word" justify_max_space_stretch="0.45" cover_page_mode="contain":
RUSTC_WRAPPER= cargo run -p epub-stream-render-web --bin web-preview -- \
{{epub}} \
--serve \
--open \
--port {{port}} \
--justify-mode {{justify_mode}} \
--justify-max-space-stretch {{justify_max_space_stretch}} \
--cover-page-mode {{cover_page_mode}}
# Export standalone HTML preview snapshot (non-interactive reflow).
web-preview-export epub="tests/fixtures/bench/pg84-frankenstein.epub" out="target/web-preview/index.html" justify_mode="adaptive-inter-word" justify_max_space_stretch="0.45" cover_page_mode="contain":
RUSTC_WRAPPER= cargo run -p epub-stream-render-web --bin web-preview -- \
{{epub}} \
--out {{out}} \
--justify-mode {{justify_mode}} \
--justify-max-space-stretch {{justify_max_space_stretch}} \
--cover-page-mode {{cover_page_mode}}
# Chapter-scoped web preview variant.
web-preview-chapter epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" out="target/web-preview/chapter.html" justify_mode="adaptive-inter-word" justify_max_space_stretch="0.45" cover_page_mode="contain":
RUSTC_WRAPPER= cargo run -p epub-stream-render-web --bin web-preview -- \
{{epub}} \
--chapter {{chapter}} \
--out {{out}} \
--justify-mode {{justify_mode}} \
--justify-max-space-stretch {{justify_max_space_stretch}} \
--cover-page-mode {{cover_page_mode}}
# One-command sane default render pass for local layout iteration.
visualize-default:
just visualize
# Render with a constrained virtual-memory budget to catch large transient
# allocations locally before flashing firmware.
visualize-lowmem epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" start="0" pages="12" out="target/visualize-lowmem" vm_kib="180000" cover_page_mode="contain":
RUSTC_WRAPPER= cargo build -p epub-stream-embedded-graphics --bin visualize --target {{ host_target }}
bash -lc "ulimit -Sv {{vm_kib}}; target/{{host_target}}/debug/visualize {{epub}} --chapter {{chapter}} --start-page {{start}} --pages {{pages}} --out {{out}} --cover-page-mode {{cover_page_mode}}"
# Low-memory smoke suite for EPUB stability validation prior to flashing.
lowmem-confidence vm_kib="150000":
just visualize-lowmem tests/fixtures/bench/pg84-frankenstein.epub 5 0 16 target/visualize-lowmem/frankenstein {{vm_kib}}
just visualize-lowmem tests/fixtures/bench/pg1342-pride-and-prejudice.epub 7 0 16 target/visualize-lowmem/pride {{vm_kib}}
just visualize-lowmem tests/fixtures/bench/pg1661-sherlock-holmes.epub 3 0 16 target/visualize-lowmem/sherlock {{vm_kib}}
just visualize-lowmem tests/fixtures/bench/pg2701-moby-dick.epub 10 0 16 target/visualize-lowmem/moby {{vm_kib}}
just visualize-lowmem tests/fixtures/Fundamental-Accessibility-Tests-Basic-Functionality-v2.0.0.epub 1 0 10 target/visualize-lowmem/fundamental {{vm_kib}}
# Same as visualize, but with inter-word justification enabled.
visualize-justify epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" start="0" pages="12" out="target/visualize-justify":
RUSTC_WRAPPER= cargo run -p epub-stream-embedded-graphics --bin visualize --target {{ host_target }} -- \
{{epub}} \
--chapter {{chapter}} \
--start-page {{start}} \
--pages {{pages}} \
--out {{out}} \
--justify
# Larger type profile for wrap/spacing validation.
visualize-large epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" start="0" pages="8" out="target/visualize-large":
RUSTC_WRAPPER= cargo run -p epub-stream-embedded-graphics --bin visualize --target {{ host_target }} -- \
{{epub}} \
--chapter {{chapter}} \
--start-page {{start}} \
--pages {{pages}} \
--out {{out}} \
--font-size 28 \
--line-gap 5 \
--paragraph-gap 10
# Deterministic typography sweep for local golden-like visual review.
visualize-matrix epub="tests/fixtures/bench/pg84-frankenstein.epub" chapter="5" start="0" pages="6":
just visualize {{epub}} {{chapter}} {{start}} {{pages}} target/visualize-matrix-default
just visualize-justify {{epub}} {{chapter}} {{start}} {{pages}} target/visualize-matrix-justify
just visualize-large {{epub}} {{chapter}} {{start}} {{pages}} target/visualize-matrix-large
# High-confidence typography gate:
# - run render-layout + typography regression tests
# - generate deterministic visual matrices for core Gutenberg fixtures
typography-confidence:
cargo test -p epub-stream-render --tests
cargo test -p epub-stream-render render_layout::tests:: -- --nocapture
just visualize tests/fixtures/bench/pg84-frankenstein.epub 5 0 8 target/visualize-confidence/frankenstein/default
just visualize-justify tests/fixtures/bench/pg84-frankenstein.epub 5 0 8 target/visualize-confidence/frankenstein/justify
just visualize-large tests/fixtures/bench/pg84-frankenstein.epub 5 0 6 target/visualize-confidence/frankenstein/large
just visualize tests/fixtures/bench/pg1342-pride-and-prejudice.epub 7 0 8 target/visualize-confidence/pride/default
just visualize-justify tests/fixtures/bench/pg1342-pride-and-prejudice.epub 7 0 8 target/visualize-confidence/pride/justify
just visualize-large tests/fixtures/bench/pg1342-pride-and-prejudice.epub 7 0 6 target/visualize-confidence/pride/large
just visualize tests/fixtures/bench/pg1661-sherlock-holmes.epub 3 0 8 target/visualize-confidence/sherlock/default
just visualize-justify tests/fixtures/bench/pg1661-sherlock-holmes.epub 3 0 8 target/visualize-confidence/sherlock/justify
just visualize-large tests/fixtures/bench/pg1661-sherlock-holmes.epub 3 0 6 target/visualize-confidence/sherlock/large
# Deterministic reflow/config regression harness for reader controls.
render-regression:
cargo test -p epub-stream-render --test corpus_regression_harness
cargo test -p epub-stream-render --test typography_regression
cargo test -p epub-stream-embedded-graphics --test embedded_reflow_regression
cargo test -p epub-stream-render --test docs
cargo test -p epub-stream-render-web --bin web-preview
# Focused embedded reflow regression harness.
embedded-reflow-regression:
cargo test -p epub-stream-embedded-graphics --test embedded_reflow_regression -- --nocapture
# Focused low-RAM loop verification inside the embedded regression harness.
embedded-low-ram-matrix:
cargo test -p epub-stream-embedded-graphics --test embedded_reflow_regression embedded_low_ram_reflow_and_page_turn_loops_are_stable -- --nocapture
# Focused budget/telemetry coverage inside the embedded regression harness.
embedded-budget-telemetry:
cargo test -p epub-stream-embedded-graphics --test embedded_reflow_regression embedded_renderer_budget_diagnostics_cover_limit_and_fallback_paths -- --nocapture
# Bootstrap external test datasets (not committed)
dataset-bootstrap:
./scripts/datasets/bootstrap.sh
# Bootstrap with explicit Gutenberg IDs (space-separated)
dataset-bootstrap-gutenberg *ids:
./scripts/datasets/bootstrap.sh {{ids}}
# List all discovered dataset EPUB files
dataset-list:
./scripts/datasets/list_epubs.sh
# Validate all dataset EPUB files
dataset-validate:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --expectations scripts/datasets/expectations.tsv
# Validate only Gutenberg EPUB corpus under tests/datasets/wild/gutenberg.
dataset-validate-gutenberg:
@cargo build --features cli --bin epub-stream
DATASET_ROOT="${EPUB_STREAM_DATASET_DIR:-tests/datasets}" && \
./scripts/datasets/validate.sh --dataset-dir "$DATASET_ROOT/wild/gutenberg" --expectations scripts/datasets/expectations.tsv
# Validate only Gutenberg EPUB corpus in strict mode.
dataset-validate-gutenberg-strict:
@cargo build --features cli --bin epub-stream
DATASET_ROOT="${EPUB_STREAM_DATASET_DIR:-tests/datasets}" && \
./scripts/datasets/validate.sh --strict --dataset-dir "$DATASET_ROOT/wild/gutenberg" --expectations scripts/datasets/expectations.tsv
# Time Gutenberg corpus smoke path (validate + chapters + first chapter text).
dataset-profile-gutenberg:
@cargo build --release --features cli --bin epub-stream
EPUB_STREAM_CLI_BIN=target/release/epub-stream ./scripts/datasets/gutenberg_smoke.sh
# Time Gutenberg corpus smoke path in strict validation mode.
dataset-profile-gutenberg-strict:
@cargo build --release --features cli --bin epub-stream
EPUB_STREAM_CLI_BIN=target/release/epub-stream ./scripts/datasets/gutenberg_smoke.sh --strict
# Full pre-flash gate including local Gutenberg corpus (if bootstrapped).
harden-gutenberg:
just all
just dataset-validate-gutenberg
just dataset-profile-gutenberg
# Validate all dataset EPUB files in strict mode (warnings fail too)
dataset-validate-strict:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --strict --expectations scripts/datasets/expectations.tsv
# Validate against expectation manifest (default mode)
dataset-validate-expected:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --expectations scripts/datasets/expectations.tsv
# Validate against expectation manifest in strict mode
dataset-validate-expected-strict:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --strict --expectations scripts/datasets/expectations.tsv
# Raw validate mode (every file must pass validation)
dataset-validate-raw:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh
# Raw strict validate mode (warnings fail too)
dataset-validate-raw-strict:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --strict
# Validate a small, CI-ready mini corpus from a manifest
dataset-validate-mini:
@cargo build --features cli --bin epub-stream
./scripts/datasets/validate.sh --manifest tests/datasets/manifest-mini.tsv
# Run benchmarks and save latest CSV report
bench:
@mkdir -p target/bench
@cargo bench --bench epub_bench --all-features | tee target/bench/latest.csv
# Check no_std + layout
check-no-std-layout:
cargo check --no-default-features --features layout
# MSRV check (matches Cargo.toml rust-version)
check-msrv:
cargo +1.85.0 check --all-features
# Clean build artifacts
clean:
cargo clean
# Crates.io publish order (dependency-aware).
publish-order:
@echo "epub-stream epub-stream-render epub-stream-embedded-graphics epub-stream-render-web"
# Local package sanity check for one crate.
package crate:
RUSTC_WRAPPER= cargo package -p {{crate}}
# Local package sanity check without dependency verification (for unpublished local deps).
package-no-verify crate:
RUSTC_WRAPPER= cargo package -p {{crate}} --no-verify
# Local package sanity check for all crates in publish order.
package-all:
just package epub-stream
just package-no-verify epub-stream-render
just package-no-verify epub-stream-embedded-graphics
just package-no-verify epub-stream-render-web
# Dry-run publish for one crate.
publish-dry-run crate:
RUSTC_WRAPPER= cargo publish -p {{crate}} --dry-run
# Dry-run publish without dependency verification (for unpublished local deps).
publish-dry-run-no-verify crate:
RUSTC_WRAPPER= cargo publish -p {{crate}} --dry-run --no-verify
# Dry-run publish for all crates in dependency order.
publish-dry-run-all:
just publish-dry-run epub-stream
just publish-dry-run-no-verify epub-stream-render
just publish-dry-run-no-verify epub-stream-embedded-graphics
just publish-dry-run-no-verify epub-stream-render-web
# Full release preflight before publishing.
release-preflight:
just ci
just package-all
just publish-dry-run-all
# Publish all crates to crates.io in dependency order.
# Requires CARGO_REGISTRY_TOKEN to be configured.
publish-all:
@bash -eu -o pipefail -c '\
crates="epub-stream epub-stream-render epub-stream-embedded-graphics epub-stream-render-web"; \
for c in $crates; do \
echo "Publishing $$c..."; \
cargo publish -p "$$c"; \
sleep 30; \
done'