midenup 0.3.2

The Miden toolchain manager
Documentation
use std::process::Command;

use cargo_toml::Manifest;

fn main() {
    let toml_contents = std::fs::read("Cargo.toml").expect("Failed to find Cargo.toml");
    let manifest =
        Manifest::from_slice(&toml_contents).expect("Failed to parse Cargo.toml as Manifest");
    let curl_version = {
        let curl = manifest
            .dependencies
            .get("curl")
            .expect("Couldn't find curl in parsed manifest");
        match curl {
            cargo_toml::Dependency::Simple(ver) => ver,
            cargo_toml::Dependency::Detailed(detail) => &detail.version.as_ref().unwrap().clone(),
            // This case should not happen since we are reading the root Cargo.toml
            cargo_toml::Dependency::Inherited(_) => {
                panic!("Couldn't determine curl version since it appears as inherited.")
            },
        }
    };
    // Pass the $CURL_VERSION to the crate at compile time.
    println!("cargo:rustc-env=CURL_VERSION={}", curl_version);

    // Pass the $TARGET to the crate at compile time.
    println!(
        "cargo:rustc-env=TARGET={}",
        std::env::var("TARGET").expect("Failed to obtain $TARGET triple constant.")
    );

    // Generated by cargo at runtime when the build script is run:
    // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
    let build_script = std::env::var("OUT_DIR").unwrap();

    write_command_to_file(&["cargo", "--version"], &(build_script.clone() + "/cargo_version.in"));
    write_command_to_file(
        &["git", "rev-parse", "--verify", "HEAD"],
        &(build_script + "/git_revision.in"),
    );
}

fn write_command_to_file(command: &[&str], file: &str) {
    let full_command =
        command.iter().fold(String::new(), |acc, argument| format!("{acc} {argument}"));

    let output = {
        let command =
            Command::new(command.first().expect("command must have at leaste one element"))
                .args(command.iter().skip(1))
                .output()
                .unwrap_or_else(|err| {
                    panic!("Couldn't run {full_command} because of: {err}");
                })
                .stdout;

        String::from_utf8(command).unwrap_or_else(|err| {
            panic!("failed to parse {full_command} output as string, because of {err}")
        })
    };

    std::fs::write(file, output.trim())
        .unwrap_or_else(|err| panic!("Failed to write to {file}: {err}"));
}