Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

holger-recipe/src/load.rs

//! **The open load of holger's declaration** — `.nornir/build-variants.toml` read and
//! validated in a tree where the COMMERCIAL `monetize-impl` checkout is absent.
//!
//! Holger is open source (owner rule): its open build must never NEED a
//! monetize-impl checkout. One row names it — the SOLD payload
//! [`METERED_PAYLOAD_VARIANT`](crate::packaging::METERED_PAYLOAD_VARIANT) consumes
//! holger's own signed monetize plugin through the edge
//! `plugin → monetize-impl/holger-guest : wasm`
//! ([`own_plugin_edge`](crate::packaging::own_plugin_edge)), declared `lazy = true`.
//! The shared load (`BuildVariantSet::discover_validated`, the same one the forge
//! runs) therefore:
//!
//! * donor present — type-checks the edge against monetize-impl's own build space;
//! * donor absent — validates every other rule and edge and leaves only the lazy
//!   edge unresolved, so the declaration (with the edge in it) loads and lists;
//!
//! and a BUILD of the sold variant with the donor absent is refused by name — by the
//! forge's edge DAG, and by `cargo xtask build` through
//! [`refuse_absent_commercial_donor`] — and only that build.

use std::path::{Path, PathBuf};

use anyhow::{anyhow, bail, Result};
use nornir_build_thing::suite_cli::{self, BuildArgs};
use nornir_build_thing::variant::BuildVariantSet;

use crate::packaging::OWN_PLUGIN_REPO;

/// Where a donor checkout `repo` would sit: beside `repo_root`.
#[must_use]
pub fn donor_root(repo_root: &Path, repo: &str) -> PathBuf {
    repo_root.parent().unwrap_or(Path::new("")).join(repo)
}

/// Whether the commercial donor checkout is beside `repo_root`.
#[must_use]
pub fn commercial_donor_present(repo_root: &Path) -> bool {
    donor_root(repo_root, OWN_PLUGIN_REPO).is_dir()
}

/// **Load and validate** `repo_root`'s declaration — the shared validated load,
/// under which the commercial edge is lazy.
///
/// # Errors
/// No declaration; any shape, on-disk-input or (eager) edge refusal.
pub fn load_declaration(repo_root: &Path) -> Result<BuildVariantSet> {
    BuildVariantSet::discover_validated(repo_root)?.ok_or_else(|| {
        anyhow!(
            "no {} — this repo declares no build space",
            BuildVariantSet::conventional_path(repo_root).display()
        )
    })
}

/// **The describe half of `cargo xtask build`** over [`load_declaration`]: the
/// lines `suite_cli` prints for `--list`, and the chosen variant names.
///
/// # Errors
/// The load's refusals, and `suite_cli::resolve`'s (unknown suite or variant).
pub fn list(repo_root: &Path, args: &BuildArgs) -> Result<(Vec<String>, Vec<String>)> {
    let set = load_declaration(repo_root)?;
    let (suite, chosen) = suite_cli::resolve(&set, args)?;
    Ok((
        suite_cli::list_lines(suite, &chosen),
        chosen.iter().map(|v| v.name.clone()).collect(),
    ))
}

/// **Refuse by name** a build of `variant` when one of its LAZY edges names a donor
/// checkout that is absent (holger's one: the sold variant's monetize-impl guest).
/// `Ok` for every open variant, and for the sold one when monetize-impl is beside
/// holger.
///
/// # Errors
/// The sold variant asked for in a tree without monetize-impl.
pub fn refuse_absent_commercial_donor(
    set: &BuildVariantSet,
    variant: &str,
    repo_root: &Path,
) -> Result<()> {
    let Some(edges) = set.edges_of(variant) else {
        return Ok(());
    };
    for (feature, e) in edges {
        let root = donor_root(repo_root, &e.repo);
        if e.lazy && !root.is_dir() {
            let what = if e.repo == OWN_PLUGIN_REPO {
                "holger's SOLD variant: its edge"
            } else {
                "a variant whose lazy edge"
            };
            bail!(
                "variant '{variant}' is {what} {feature} → {} : {} is built by the {} checkout, and \
                 there is none beside holger ({} is not a directory). The open build never needs \
                 it; build an open variant, or put the {} checkout there to build this one.",
                e.coordinate(),
                e.typ.as_str(),
                e.repo,
                root.display(),
                e.repo
            );
        }
    }
    Ok(())
}