Expand description
All builders for the site (ex: cargo build, cargo doc, etc.).
Builder types, the [Builder] trait, and the parallel execution model.
Each [[builders]] entry in abbaye.toml deserialises into a
BuilderEntry and is run as an independent Tokio task. This module
owns the AnyBuilder enum (the TOML type-tag dispatch), the
[LogEvent] channel used for progress-bar updates, and the [Builder]
trait that every concrete builder must implement.
§Parallel Builder Execution
This section explains how Abbaye runs the [[builders]] entries defined in
abbaye.toml in parallel, how inter-builder dependencies are enforced, and
how the progress UI is kept in sync with the running tasks.
§Overview
Every [[builders]] entry is executed as an independent Tokio async task.
Tasks are launched at the same time (via a shared JoinSet) and may
therefore run fully concurrently. When a builder declares depends_on,
its task simply waits — without blocking any thread — until all named
prerequisites have completed successfully before invoking the underlying
build logic.
§Configuration Model
§BuilderEntry
Each [[builders]] table in the TOML file deserialises into a
BuilderEntry:
| Field | Type | Purpose |
|---|---|---|
builder | AnyBuilder | Type-tagged union holding the builder’s own config (flattened). |
id | Option<String> | Stable name that other builders can reference in depends_on. |
depends_on | Vec<String> | IDs of builders that must succeed before this one starts. |
Example:
[[builders]]
type = "cargo"
id = "compile"
[[builders]]
type = "script"
script = ["strip target/release/mybin"]
outputs = ["target/release/mybin"]
depends_on = ["compile"] # waits for the cargo builder above§AnyBuilder variants
TOML type | Rust variant | What it does |
|---|---|---|
archive | Archive | Creates a .tar.gz of the source tree. |
cargo | Cargo | cargo build --release, optionally for multiple targets. |
cargo_doc | CargoDoc | cargo doc. |
markdown | Markdown | Renders a directory of .md files to HTML. |
script | Script | Runs an arbitrary sequence of sh -c commands. |
§Orchestration in build_site (src/site.rs)
The entire builder pipeline lives inside build_site, in three phases.
§Phase 1 — Validation
Before any task is spawned, two checks are performed:
-
Reference check — every string in
depends_onmust match anidof some other builder in the same config. Unknown IDs are reported as a hard error immediately. -
Cycle detection — a depth-first search visits the dependency graph and returns an error if a cycle is found.
The DFS tracks three states per node: 0 = unvisited, 1 = in the current stack, 2 = fully processed. Encountering a node in state 1 means
there is a back-edge, i.e. a cycle.
§Phase 2 — Completion channels
For each builder that carries an id, a tokio::sync::watch channel is
created:
watch::channel(None::<bool>)
↑
└─ initial value: None (pending)The channel is later sent Some(true) (success) or Some(false)
(failure). Dependents hold a cloned Receiver and call
wait_for(|v| v.is_some()), which suspends the task cooperatively until
the value changes.
If a dependency’s watch::Sender is dropped without ever sending a value
(e.g. the task panicked), wait_for returns an Err, which is treated as
a failure and the dependent is skipped.
§Phase 3 — Task spawning and collection
All tasks are submitted to a single tokio::task::JoinSet. Every task
follows the same lifecycle:
- Spawned → waits for all declared dependencies.
- Running → all deps succeeded; the builder executes.
- Skipped → a dependency failed; returns
Ok(vec![])and signalsSome(false)so its own dependents also skip. - Done / Failed → signals
Some(true)orSome(false).
After all tasks finish, collected [ArtifactPath]s are classified:
- File artifacts →
dist/(distribution binaries, archives, etc.). - Directory artifacts →
docs/(rustdoc output, rendered Markdown, …).
If any builder returned an error, the first error is propagated to the caller after all spinners have settled, so the full UI is always rendered to completion.
§Progress UI
The UI is built with the indicatif crate. Each builder task owns:
- A parent spinner inserted above a shared summary bar.
- An mpsc log channel ([
LogSender]) over which the builder streams events. - A log-consumer task that receives [
LogEvent]s and updates the spinner.
§LogEvent variants
| Variant | Meaning |
|---|---|
Line(String) | Update the parent spinner message. |
ChildStart { id, label } | Create a sub-spinner below the parent. |
ChildLine { id, line } | Update a child spinner’s message. |
ChildFinish { id, … } | Close a child spinner with ✓ or ✗. |
The ChildStart / ChildLine / ChildFinish events are used only by the
cargo builder when it compiles for multiple targets in parallel (see
below).
§Inner Parallelism: CargoBuilder
When a cargo builder lists multiple targets, it spawns one Tokio task
per target inside its own inner JoinSet — a second level of concurrency
nested inside the outer builder task.
Each inner task:
- Creates a
tempfile::TempDirand passes it as--target-dirso thecargo buildprocess does not contend with sibling builds on cargo’s file lock. - Emits a
ChildStartevent so the UI creates a dedicated sub-spinner. - Uses
line_bridgeto adapt the plain-string stderr stream fromrun_cargo_buildintoChildLineevents on the parent [LogSender]. - After the build, copies artifacts to stable
target/<triple>/release/paths before theTempDiris dropped. - Emits a
ChildFinishevent when done.
Within run_cargo_build itself, stderr and the JSON stdout are consumed
concurrently in separate tokio::spawn tasks so neither stream blocks the
other.
§Other Builders
| Builder | Async strategy |
|---|---|
archive | tokio::task::spawn_blocking for the CPU-bound tar walk; sends Line events. |
cargo_doc | Spawns one tokio::spawn to stream stderr; awaits cargo doc exit. |
markdown | Sequential per-file render loop; spawn_blocking for the directory walk. |
script | Runs commands sequentially; streams stdout and stderr in parallel tasks. |
Modules§
Structs§
- Artifact
Path - Builder
Entry - A single
[[builders]]entry: the builder itself plus optional dependency metadata.
Enums§
- AnyBuilder
- LogEvent
- Events emitted by builders and forwarded to the progress-bar manager in
crate::site.
Traits§
- Builder
- Implementing a New Builder
Type Aliases§
- LogSender
- A sender used to stream
LogEvents from a builder back to the progress-bar manager incrate::site. Errors sending are silently ignored because the receiver may already be gone when a builder finishes.