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

nordisk/holger

xtask/src/twin.rs

//! **`cargo xtask twin [--row <product>]…`: each product's row and its `cargo install` line
//! build the same binary** (Holger v2.0 H5, docs/HOLGER-V2.md: "reproducible, both ways";
//! the four products since HOL-PRODUCTS).
//!
//! For every product of `holger_recipe::twins::PRODUCTS` (or the ones named):
//!
//! 1. the row is built by the Build Thing (`build_variant_in_container`, the pinned image,
//!    `--offline --locked`, the remapped paths);
//! 2. its `cargo install` line runs in the SAME image, from the same checkout, into a
//!    second target dir that the container sees at the same path (`/target`), so the
//!    remapped paths are the same and nothing but the command differs;
//! 3. the two binaries are compared byte for byte. A difference is named: the sizes, how
//!    many bytes differ and where the first one is.
//!
//! `holger-ui` lives in the holger-ui repository: it is checked only when `../holger-ui` is
//! checked out beside holger (its install line then runs there, `--path crates/holger-ui`),
//! and skipped by name otherwise.
//!
//! `tests/rows_equal_cargo_install.rs` (holger-recipe) holds the two COMMANDS equal on
//! every test run; this verb holds the two BINARIES equal, which needs a container engine.

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

use anyhow::{bail, Context, Result};
use nornir_build_thing::cargo_container::{self as cc, CargoInvocation, RunEnv};

/// Where the twin's `cargo install --root` puts its bin, inside the container.
pub const INSTALL_ROOT: &str = "/target/twin-root";

/// Pure: the container argv of an install line. `cargo` is dropped (the script adds it),
/// `--locked` too (the script appends it, and cargo refuses it twice), and the install
/// goes to [`INSTALL_ROOT`] with the container's target dir, so its paths are the row's.
pub fn container_install_args(line: &str) -> Vec<String> {
    let mut a: Vec<String> = line
        .split_whitespace()
        .skip(1)
        .filter(|w| *w != "--locked")
        .map(String::from)
        .collect();
    a.extend([
        "--root".to_string(),
        INSTALL_ROOT.to_string(),
        "--target-dir".into(),
        cc::TARGETDIR.to_string(),
    ]);
    a
}

/// How two binaries compare.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Identity {
    Identical {
        bytes: u64,
    },
    Differ {
        row: u64,
        install: u64,
        differing: u64,
        first_at: u64,
    },
}

/// Pure: compare the row's bytes with the install's.
pub fn compare(row: &[u8], install: &[u8]) -> Identity {
    if row == install {
        return Identity::Identical {
            bytes: row.len() as u64,
        };
    }
    let common = row.len().min(install.len());
    let tail = (row.len().max(install.len()) - common) as u64;
    let differing = tail + row.iter().zip(install).filter(|(a, b)| a != b).count() as u64;
    let first_at = row
        .iter()
        .zip(install)
        .position(|(a, b)| a != b)
        .unwrap_or(common) as u64;
    Identity::Differ {
        row: row.len() as u64,
        install: install.len() as u64,
        differing,
        first_at,
    }
}

/// Pure: the products to check: the named ones (each must be a product), or all of them.
pub fn chosen_rows(args: &[String]) -> Result<Vec<&'static holger_recipe::twins::Product>> {
    let mut names = Vec::new();
    let mut it = args.iter();
    while let Some(a) = it.next() {
        match a.as_str() {
            "--row" => names.push(it.next().context("`--row` needs a row name")?.clone()),
            other => {
                bail!("twin: unknown argument `{other}` (usage: cargo xtask twin [--row <row>]…)")
            }
        }
    }
    let all = holger_recipe::twins::PRODUCTS;
    if names.is_empty() {
        return Ok(all.iter().collect());
    }
    names
        .iter()
        .map(|n| all.iter().find(|r| r.name == n).with_context(|| format!("`{n}` is no product (the products: holger, holger-downstream, holger-ui, holger-cli)")))
        .collect()
}

/// Where a product's install line runs, and the line: holger's root for its own crates;
/// the holger-ui checkout beside it for the console (`None` when it is not there).
pub fn install_at(root: &Path, r: &holger_recipe::twins::Product) -> Option<(PathBuf, String)> {
    if r.name == holger_recipe::variants::HOLGER_UI {
        let ui = root.join("../holger-ui");
        return ui.join("crates/holger-ui/Cargo.toml").is_file().then(|| {
            (
                ui,
                "cargo install --locked --path crates/holger-ui".to_string(),
            )
        });
    }
    Some((root.to_path_buf(), r.install.to_string()))
}

/// The verb. `Ok(true)` when every row's binary is its install's, byte for byte.
pub fn run(root: &Path, args: &[String]) -> Result<bool> {
    let rows = chosen_rows(args)?;
    let road = crate::cargo_road(root)?;
    let set = holger_build_space::build_variant_set()?;
    let twin_target = PathBuf::from(format!("{}-twin", road.target_dir.display()));
    std::fs::create_dir_all(&twin_target)?;
    let mut all_same = true;
    let mut lines = Vec::new();
    for r in rows {
        let Some((install_root, install)) = install_at(root, r) else {
            let line = format!(
                "{}: skipped, ../holger-ui is not checked out beside holger",
                r.name
            );
            println!("{line}");
            lines.push(line);
            continue;
        };
        let v = set.require(r.name)?;
        let bin = v
            .bin
            .clone()
            .with_context(|| format!("row `{}` names no bin", r.name))?;
        println!("\n=== twin `{}`: the row ===", r.name);
        let out = cc::build_variant_in_container(
            &set,
            r.name,
            root,
            &road.target_dir,
            road.registry.as_deref(),
            &road.tc,
            &road.runner,
        )?;
        if !out.success {
            bail!("the row `{}` did not build", r.name);
        }
        let row_bin = out
            .artifacts
            .iter()
            .find(|p| p.file_name().and_then(|f| f.to_str()) == Some(bin.as_str()))
            .cloned()
            .with_context(|| {
                format!(
                    "the row `{}` produced no `{bin}`: {:?}",
                    r.name, out.artifacts
                )
            })?;
        println!("=== twin `{}`: {install} ===", r.name);
        let run = cc::run_cargo_in_container(
            &road.tc,
            &CargoInvocation {
                label: format!("twin-{}", r.name),
                repo_root: install_root,
                target_dir: twin_target.clone(),
                registry: road.registry.clone(),
                cargo_args: container_install_args(&install),
                cfg: v.cfg.clone(),
                env: RunEnv::new(),
                extra_binds: Vec::new(),
            },
            &road.runner,
        )?;
        if !run.success() {
            bail!(
                "`{install}` did not build in the container:\n{}",
                run.outcome.stderr.join("\n")
            );
        }
        let install_bin = twin_target.join("twin-root/bin").join(&bin);
        let (a, b) = (
            std::fs::read(&row_bin).with_context(|| format!("read {}", row_bin.display()))?,
            std::fs::read(&install_bin)
                .with_context(|| format!("read {}", install_bin.display()))?,
        );
        let line = match compare(&a, &b) {
            Identity::Identical { bytes } => format!(
                "{}: row = `{install}`: byte-identical, {bytes} bytes",
                r.name
            ),
            Identity::Differ {
                row,
                install: install_n,
                differing,
                first_at,
            } => {
                all_same = false;
                format!(
                    "{}: row != `{install}`: {row} against {} bytes, {differing} differ, the first at offset {first_at} ({} and {})",
                    r.name,
                    install_n,
                    row_bin.display(),
                    install_bin.display()
                )
            }
        };
        println!("{line}");
        lines.push(line);
    }
    println!("\n=== twin ===\n{}", lines.join("\n"));
    Ok(all_same)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn the_install_runs_into_the_containers_target_dir_and_names_lock_once() {
        let a = container_install_args(
            "cargo install --locked --path holger-downstream --features full",
        );
        assert_eq!(
            a,
            [
                "install",
                "--path",
                "holger-downstream",
                "--features",
                "full",
                "--root",
                INSTALL_ROOT,
                "--target-dir",
                "/target"
            ]
        );
        assert!(
            INSTALL_ROOT.starts_with(cc::TARGETDIR),
            "the installed bin lands in the mounted twin target"
        );
    }

    #[test]
    fn identical_bytes_are_identical_and_a_difference_is_located() {
        assert_eq!(compare(b"abc", b"abc"), Identity::Identical { bytes: 3 });
        assert_eq!(
            compare(b"abcd", b"abxd"),
            Identity::Differ {
                row: 4,
                install: 4,
                differing: 1,
                first_at: 2
            }
        );
        assert_eq!(
            compare(b"ab", b"abcd"),
            Identity::Differ {
                row: 2,
                install: 4,
                differing: 2,
                first_at: 2
            }
        );
    }

    #[test]
    fn every_product_is_checked_unless_some_are_named() {
        assert_eq!(chosen_rows(&[]).unwrap().len(), 4);
        let one = chosen_rows(&["--row".into(), "holger-downstream".into()]).unwrap();
        assert_eq!(
            one.iter().map(|r| r.name).collect::<Vec<_>>(),
            ["holger-downstream"]
        );
        assert!(
            chosen_rows(&["--row".into(), "mvp-server-musl".into()]).is_err(),
            "only a product has a twin"
        );
        assert!(chosen_rows(&["--all".into()]).is_err());
    }

    #[test]
    fn the_console_installs_from_the_holger_ui_checkout_or_is_skipped() {
        let tmp = tempfile::tempdir().unwrap();
        let root = tmp.path().join("holger");
        std::fs::create_dir_all(&root).unwrap();
        let ui = holger_recipe::twins::PRODUCTS
            .iter()
            .find(|r| r.name == "holger-ui")
            .unwrap();
        assert!(
            install_at(&root, ui).is_none(),
            "no holger-ui beside: skipped"
        );
        std::fs::create_dir_all(tmp.path().join("holger-ui/crates/holger-ui")).unwrap();
        std::fs::write(tmp.path().join("holger-ui/crates/holger-ui/Cargo.toml"), "").unwrap();
        let (at, line) = install_at(&root, ui).unwrap();
        assert!(at.ends_with("holger/../holger-ui"), "{}", at.display());
        assert_eq!(line, "cargo install --locked --path crates/holger-ui");
        let server = holger_recipe::twins::PRODUCTS
            .iter()
            .find(|r| r.name == "holger")
            .unwrap();
        assert_eq!(
            install_at(&root, server).unwrap(),
            (
                root.clone(),
                "cargo install --locked --path server/cli".to_string()
            )
        );
    }
}