presolve-cli 0.2.0-beta.1

The Presolve compiler and application command-line interface.
Documentation
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};

use serde::Deserialize;

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct RepresentativeCorpus {
    schema_version: u32,
    suite: String,
    applications: Vec<RepresentativeApplication>,
}

#[derive(Deserialize)]
struct RepresentativeApplication {
    name: String,
    root: String,
    evidence: Vec<String>,
}

fn repository_root() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("../..")
        .canonicalize()
        .expect("repository root")
}

static NEXT_ROOT: AtomicUsize = AtomicUsize::new(1);

fn copy_tree(source: &Path, destination: &Path) {
    std::fs::create_dir_all(destination).expect("representative destination directory");
    for entry in std::fs::read_dir(source).expect("representative source directory") {
        let entry = entry.expect("representative source entry");
        let target = destination.join(entry.file_name());
        if entry
            .file_type()
            .expect("representative entry type")
            .is_dir()
        {
            copy_tree(&entry.path(), &target);
        } else {
            std::fs::copy(entry.path(), target).expect("copy representative source file");
        }
    }
}

fn find_artifact(root: &Path, name: &str) -> Option<PathBuf> {
    for entry in std::fs::read_dir(root).ok()? {
        let entry = entry.ok()?;
        let path = entry.path();
        if path.file_name().is_some_and(|file_name| file_name == name) {
            return Some(path);
        }
        if entry.file_type().ok()?.is_dir() {
            if let Some(path) = find_artifact(&path, name) {
                return Some(path);
            }
        }
    }
    None
}

#[test]
fn representative_applications_publish_routes_resume_and_production_audits() {
    let root = repository_root();
    let corpus: RepresentativeCorpus = serde_json::from_str(include_str!(
        "../../../fixtures/representative-applications.json"
    ))
    .expect("representative corpus JSON");
    assert_eq!(corpus.schema_version, 1);
    assert_eq!(corpus.suite, "presolve-representative-applications");
    assert_eq!(corpus.applications.len(), 2);
    for application in corpus.applications {
        assert!(application
            .evidence
            .contains(&"production-build".to_string()));
        let temporary_root = std::env::temp_dir().join(format!(
            "presolve-representative-{}-{}-{}",
            application.name,
            std::process::id(),
            NEXT_ROOT.fetch_add(1, Ordering::Relaxed)
        ));
        copy_tree(&root.join(application.root), &temporary_root);
        let output = temporary_root.join("dist");
        let result = Command::new(env!("CARGO_BIN_EXE_presolve"))
            .current_dir(&temporary_root)
            .arg("build")
            .output()
            .expect("representative application build");
        assert!(
            result.status.success(),
            "{} build failed: {}",
            application.name,
            String::from_utf8_lossy(&result.stderr)
        );
        assert!(find_artifact(&output, "resume.runtime.json").is_some());
        let audit_path =
            find_artifact(&output, "production-audit.json").expect("route-scoped production audit");
        let audit: serde_json::Value =
            serde_json::from_slice(&std::fs::read(audit_path).expect("production audit"))
                .expect("production audit JSON");
        assert_eq!(audit["status"], "passed");
        std::fs::remove_dir_all(temporary_root).expect("remove representative project");
    }
}