git-ents.gitmain
⌘K
foforge
lib.rs95 lines · 4.1 KB · rusthistorycomment on this file
1//! The toolchain domain: the [`Toolchain`] entity and its
2//! resolution/materialization machinery (`model.toolchain`,
3//! `effect.toolchains`), plus the `toolchain` porcelain command —
4//! kernel-independent, unlike `ents-model`'s remaining entities, because
5//! resolving a toolchain needs `ents-effect` (to share its tree-checkout
6//! primitive and its `Error`/`Result` type) and `ents-receive` (to propose
7//! the import mutation), neither of which a purely declarative vocabulary
8//! crate like `ents-model` may depend on.
9//!
10//! This crate sits *above* the kernel in the dependency graph, not inside
11//! it: `ents-model`, `ents-anchor`, `ents-gate`, `ents-query`,
12//! `ents-receive`, `ents-effect`, `ents-sync`, and `ents-testutil` must
13//! never depend on `ents-kiln` (verified by `grep -rn ents-kiln
14//! crates/kernel crates/substrate` finding nothing) — `ents-kiln` depends
15//! on them, never the reverse. `git-ents` (the CLI) depends on this crate
16//! and mounts its toolchain command through a thin wrapper that only adds
17//! signer/actor construction and CLI-facing error rendering, and resolves
18//! an effect's declared toolchains through this crate before calling
19//! `ents_effect::run::run_effect` (`crate::commands::effect::run` on the
20//! CLI side).
21//!
22//! # Spec coverage
23//!
24//! From `docs/spec/model.sdoc` and `docs/spec/effect.adoc`:
25//!
26//! - `model.toolchain` — [`Toolchain`].
27//! - `effect.toolchains` — [`Recipe`], [`Component`], [`toolchain::resolve`],
28//! [`toolchain::cache_key`], [`toolchain::materialize`]: reading a
29//! toolchain manifest, parsing its `recipe`, and extracting it to a host
30//! directory. `ents_effect::run::run_one`/`run_effect` no longer resolve
31//! toolchain names themselves — they accept an already-materialized
32//! `&[(String, PathBuf)]` slice; resolving an effect's declared names to
33//! that slice is this crate's job, done by a composition root before it
34//! calls into `ents-effect`'s run loop.
35//! - `meta-ref.typed-tree` — `toolchain::entity`'s round-trip test (see
36//! the module itself for the concrete test, folded into `toolchain`'s
37//! private `entity` submodule).
38//!
39//! # Examples
40//!
41//! Import a toolchain (embedding a stand-in tree — `ents-kiln`'s own
42//! `command::import` walks a real host directory; this example embeds an
43//! already-written tree directly to demonstrate just the entity/recipe
44//! round trip) and resolve it back.
45//!
46//! ```
47//! use ents_kiln::{Recipe, Toolchain, toolchain};
48//! use ents_testutil::{MemRefStore, ObjectStore, write_meta_entity};
49//! use gix_object::{Kind, Write as _};
50//!
51//! let refs = MemRefStore::default();
52//! let objects = ObjectStore::default();
53//! let bin_tree = objects.write_buf(Kind::Tree, b"").expect("write");
54//!
55//! let toolchain = Toolchain {
56//! name: "rust-stable".into(),
57//! recipe: Recipe::Embedded { tree: bin_tree }.render(),
58//! };
59//! let name: gix::refs::FullName = "refs/meta/toolchains/rust-stable".try_into().expect("valid");
60//! write_meta_entity(&refs, &objects, name, &toolchain, None, 100);
61//!
62//! let (entity, recipe) = toolchain::resolve(&refs, &objects, "rust-stable").expect("resolves");
63//! assert_eq!(entity.name, "rust-stable");
64//!
65//! let cache = tempfile::tempdir().expect("tempdir");
66//! let bin = toolchain::materialize(&recipe, &objects, cache.path()).expect("materializes");
67//! assert!(bin.is_dir());
68//! ```
69
70pub mod toolchain;
71
72pub use toolchain::{Component, Recipe, Toolchain, cache_key, materialize, resolve};
73
74#[cfg(test)]
75mod tests {
76 use facet::Facet as _;
77 use rstest::rstest;
78
79 use super::*;
80
81 /// The entity that moved from `ents-model` to this crate keeps the
82 /// same `model.extensibility` guarantee `ents_model`'s own shape test
83 /// pins for its remaining entities (and `ents-forge`'s own copy pins
84 /// for `Comment`/`Issue`): its reflected
85 /// [`facet::Shape::type_identifier`] is exactly its Rust struct name.
86 #[rstest]
87 #[case::toolchain(Toolchain::SHAPE.type_identifier, "Toolchain")]
88 // @relation(model.extensibility, scope=function, role=Verifies)
89 fn every_entity_shape_name_tracks_its_struct_declaration(
90 #[case] reflected: &str,
91 #[case] expected: &str,
92 ) {
93 assert_eq!(reflected, expected);
94 }
95}