Skip to main content

cove_rules_check/
check.rs

1//! `cove check`, for a rule package written against this application's own
2//! host module.
3//!
4//! # Why this exists
5//!
6//! The person who writes rules is not the person who wrote the embedder. Their
7//! toolchain is `cove fmt`, `cove check` and `cove test`, and `cove check`
8//! stops at `use reviews`:
9//!
10//! ```text
11//! warning[cove::resolve::unchecked_host]: no Host API schema describes the
12//! host module `reviews`, so calls into it are unchecked
13//! ```
14//!
15//! which is accurate. `reviews` is this crate's, and no `cove` command has
16//! heard of it. Issue #151 asked for a flag or a `cove.toml` key that would
17//! let one; `cove_sema::compile`'s module doc is where the answer is argued,
18//! and the answer is no. A description in a config file is a second
19//! description of a module whose first one is Rust, and two descriptions of
20//! one thing is the drift ADR 0017 exists to prevent; and a schema would let
21//! `cove check` check a package that `cove test` still could not run, because
22//! what answers a call is an implementation and no format carries one.
23//!
24//! So the toolchain is the embedder's to provide, and this is the whole of it.
25//! It is not a fork of `cove check`: it reads the same package from disk, runs
26//! the same `cove_sema::Compiler`, and renders diagnostics with the same
27//! `cove_diag::render`, with one line's difference — the schemas it was handed.
28//!
29//! ```console
30//! $ cargo run -p cove-rules --bin cove-rules-check
31//! `rules` checks against `reviews`: 10 files, 6 modules, no notices
32//! ```
33//!
34//! # What it does not do
35//!
36//! It does not run the package's `test fn` declarations. That needs the
37//! `reviews` *implementation* as well as its description, which is the same
38//! argument arriving from the other end: an embedder that wants `cove test`
39//! registers [`cove_rules::Reviews`] beside the schema and runs the tests
40//! against it. Nothing in the way stops that; it is simply more than one line,
41//! and this file is the one-line half.
42
43use std::process::ExitCode;
44
45use cove_rules::{package_root, RulePackage, REVIEWS};
46
47fn main() -> ExitCode {
48    // The same value `Reviews::module_schema` answers with. That it is one
49    // value is the whole point: a checker reading a copy of the description
50    // the boundary enforces would be a checker that can be right about a
51    // module the run is not going to have.
52    let package = match RulePackage::load(&package_root(), REVIEWS) {
53        Ok(package) => package,
54        Err(report) => {
55            eprint!("{report}");
56            return ExitCode::FAILURE;
57        }
58    };
59
60    let notices = package.notices();
61    for notice in &notices {
62        eprint!("{notice}");
63    }
64
65    let cost = package.cost();
66    let count = match notices.len() {
67        0 => "no notices".to_string(),
68        1 => "1 notice".to_string(),
69        many => format!("{many} notices"),
70    };
71    println!(
72        "`rules` checks against `{}`: {} files, {} modules, {count}",
73        REVIEWS.name, cost.files, cost.modules
74    );
75    ExitCode::SUCCESS
76}