src/code_room/driver.rs
//! Where the nightly driver is on THIS box, and whether it can run
//! (decision D6, wiring map I5).
//!
//! The driver is a separate nightly artifact — `cargo-mimir-dump` + its
//! sibling `mimir-driver` + the pinned toolchain with `rustc-dev` — that the
//! stable workspace never builds. A dev box has it installed; a server box
//! runs it from the pinned toolchain IMAGE (an ops-kit step). This module
//! finds the pair, hands the consumer a probed [`DriverReady`], and turns
//! everything else into the typed [`State::DriverNotAvailable`] with the
//! step that failed — before a single commit is touched.
//!
//! | setting | meaning |
//! |---|---|
//! | `NORNIR_MIMIR_DRIVER` | path of `cargo-mimir-dump` (its sibling `mimir-driver` is the wrapper) |
//! | `NORNIR_MIMIR_DRIVER_HOST` | wrapper command line every tool is started through — the toolchain image, e.g. `podman run --rm -v /home/nornir/.nornir:/home/nornir/.nornir nordisk-cargo-toolchain:pinned`; the driver path is then a path INSIDE the image |
//! | `NORNIR_MIMIR_TOOLCHAIN` | the nightly the driver was built against, when it is not the one this tree pins |
//! | `NORNIR_MIMIR_CONTAINER_IMAGE` (+ `…_DRIVER`, `…_BINDS`) | the CONTAINER road ([`super::container`]): every tool in that image through draupnir; tried first, the host road said and taken when it does not work |
//!
//! Without `NORNIR_MIMIR_DRIVER` the pair is looked for, in order, at
//! `<nornir home>/mimir-driver/`, beside the running binary, and on `PATH`.
use std::path::{Path, PathBuf};
use mimir_ingest::{DriverHost, DriverReady, DriverSpec, pinned_toolchain};
use super::{Refusal, State};
pub const ENV_DRIVER: &str = "NORNIR_MIMIR_DRIVER";
pub const ENV_DRIVER_HOST: &str = "NORNIR_MIMIR_DRIVER_HOST";
pub const ENV_TOOLCHAIN: &str = "NORNIR_MIMIR_TOOLCHAIN";
const TOOL: &str = "cargo-mimir-dump";
/// What the settings + the box resolve to.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Settings {
pub driver: Option<PathBuf>,
pub host: Option<String>,
pub toolchain: Option<String>,
/// Directories searched when `driver` is unset (in order).
pub search: Vec<PathBuf>,
}
impl Settings {
/// From the environment and this process's surroundings.
pub fn from_env() -> Self {
let non_empty = |k: &str| std::env::var(k).ok().map(|v| v.trim().to_string()).filter(|v| !v.is_empty());
let mut search = vec![crate::config::nornir_home().join("mimir-driver")];
if let Some(dir) = std::env::current_exe().ok().and_then(|p| p.parent().map(Path::to_path_buf)) {
search.push(dir);
}
search.extend(std::env::var_os("PATH").map(|p| std::env::split_paths(&p).collect::<Vec<_>>()).unwrap_or_default());
Self { driver: non_empty(ENV_DRIVER).map(PathBuf::from), host: non_empty(ENV_DRIVER_HOST), toolchain: non_empty(ENV_TOOLCHAIN), search }
}
/// Which driver to run and where. No process is started: that is the probe.
pub fn locate(&self) -> Result<DriverSpec, Refusal> {
let host = match &self.host {
Some(line) => DriverHost::Wrapped(line.split_whitespace().map(str::to_string).collect()),
None => DriverHost::Installed,
};
let toolchain = self.toolchain.clone().unwrap_or_else(|| pinned_toolchain().to_string());
let cargo_mimir_dump = match (&self.driver, &host) {
(Some(p), _) => p.clone(),
// inside the image the tool is on PATH unless told otherwise
(None, DriverHost::Wrapped(_) | DriverHost::Runner(_)) => PathBuf::from(TOOL),
(None, DriverHost::Installed) => self.search.iter().map(|d| d.join(TOOL)).find(|p| p.is_file()).ok_or_else(|| {
Refusal::new(
State::DriverNotAvailable,
format!(
"the Mímir driver is not installed: no `{TOOL}` in {} — set {ENV_DRIVER} to it, or \
{ENV_DRIVER_HOST} to run it from the pinned toolchain image (toolchain {toolchain})",
self.search.iter().take(2).map(|d| d.display().to_string()).collect::<Vec<_>>().join(", "),
),
)
})?,
};
Ok(DriverSpec { cargo_mimir_dump, driver: None, toolchain, host })
}
/// Locate, then prove it runs (`DriverSpec::probe`).
pub fn probe(&self) -> Result<DriverReady, Refusal> {
// the CONTAINER road first when an image is named; when it does not
// work, say so and read on the host — never silently
#[cfg(feature = "mimir-container")]
if let Some(road) = super::container::ContainerRoad::from_env() {
let toolchain = self.toolchain.clone().unwrap_or_else(|| pinned_toolchain().to_string());
let spec = DriverSpec {
cargo_mimir_dump: road.cargo_mimir_dump(),
driver: None,
toolchain,
host: DriverHost::Runner(mimir_ingest::RunnerHandle(std::sync::Arc::new(super::container::BoxRoad::new(road.clone())))),
};
match spec.probe() {
Ok(ready) => {
eprintln!("nornir-consumer: Mímir driver on the CONTAINER road: {} · {} · {}", road.image, road.cargo_mimir_dump().display(), ready.rustc);
return Ok(ready);
}
Err(e) => eprintln!(
"nornir-consumer: Mímir driver: the CONTAINER road ({}, driver {}) does not work — {e}; reading on the HOST road",
road.image,
road.cargo_mimir_dump().display()
),
}
}
let spec = self.locate()?;
spec.probe().map_err(|e| {
Refusal::new(
State::DriverNotAvailable,
format!("the Mímir driver cannot run here ({}; host {}): {e}", spec.cargo_mimir_dump.display(), spec.host.describe()),
)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn settings(search: Vec<PathBuf>) -> Settings {
Settings { driver: None, host: None, toolchain: None, search }
}
#[test]
fn no_driver_anywhere_is_driver_not_available_naming_where_it_looked() {
let dir = tempfile::tempdir().unwrap();
let r = settings(vec![dir.path().to_path_buf()]).probe().unwrap_err();
assert_eq!(r.state, State::DriverNotAvailable);
assert!(r.note.contains("not installed") && r.note.contains(&dir.path().display().to_string()), "{r}");
assert!(r.note.contains(ENV_DRIVER) && r.note.contains(pinned_toolchain()), "{r}");
}
#[test]
fn the_first_search_dir_that_holds_the_tool_wins_and_the_pin_is_the_default_toolchain() {
let (a, b) = (tempfile::tempdir().unwrap(), tempfile::tempdir().unwrap());
std::fs::write(b.path().join(TOOL), b"").unwrap();
let spec = settings(vec![a.path().to_path_buf(), b.path().to_path_buf()]).locate().unwrap();
assert_eq!(spec.cargo_mimir_dump, b.path().join(TOOL));
assert_eq!((spec.toolchain.as_str(), &spec.host), (pinned_toolchain(), &DriverHost::Installed));
assert_eq!(spec.driver_path(), b.path().join("mimir-driver"));
}
#[test]
fn a_host_line_wraps_the_tool_and_needs_no_local_binary() {
let s = Settings {
driver: None,
host: Some("podman run --rm -v /srv:/srv img:pinned".into()),
toolchain: Some("nightly-2026-01-01".into()),
search: vec![],
};
let spec = s.locate().unwrap();
assert_eq!(spec.host, DriverHost::Wrapped(["podman", "run", "--rm", "-v", "/srv:/srv", "img:pinned"].map(String::from).to_vec()));
assert_eq!((spec.cargo_mimir_dump, spec.toolchain.as_str()), (PathBuf::from(TOOL), "nightly-2026-01-01"));
}
/// A pair that is on disk but cannot run (here: empty files, and a nightly
/// nobody has) is the same state with the probe's step in the sentence.
#[test]
fn a_driver_that_does_not_probe_is_driver_not_available_with_the_step() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join(TOOL), b"").unwrap();
std::fs::write(dir.path().join("mimir-driver"), b"").unwrap();
let mut s = settings(vec![dir.path().to_path_buf()]);
s.toolchain = Some("nightly-1999-01-01".into());
let r = s.probe().unwrap_err();
assert_eq!(r.state, State::DriverNotAvailable);
assert!(r.note.contains("cannot run here") && r.note.contains("nightly-1999-01-01 is not installed"), "{r}");
}
}