hyperstack-macros 0.6.9

Proc-macros for defining HyperStack streams
Documentation
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};

use tempfile::TempDir;

pub fn escape_path(path: &Path) -> String {
    path.display().to_string().replace('\\', "\\\\")
}

pub fn macro_manifest_dir() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}

pub fn workspace_root() -> PathBuf {
    macro_manifest_dir()
        .parent()
        .expect("hyperstack-macros should live in workspace root")
        .to_path_buf()
}

#[allow(dead_code)]
pub fn hyperstack_dir() -> PathBuf {
    workspace_root().join("hyperstack")
}

pub fn cargo_toml(name: &str, dependencies: &[String]) -> String {
    let dependencies = dependencies.join("\n");

    format!(
        r#"[package]
name = "{name}"
version = "0.0.0"
edition = "2021"

[workspace]

[dependencies]
{dependencies}
"#
    )
}

pub struct TempCrate {
    workspace_root: PathBuf,
    temp_dir: TempDir,
}

impl TempCrate {
    pub fn new(
        test_subdir: &str,
        name: &str,
        cargo_toml: String,
        source: &str,
        extra_files: &[(&str, &str)],
    ) -> Self {
        let workspace_root = workspace_root();
        let temp_root = workspace_root.join("target/tests").join(test_subdir);
        fs::create_dir_all(&temp_root).expect("create dynamic test root");

        let temp_dir = tempfile::Builder::new()
            .prefix(&format!("{name}-"))
            .tempdir_in(&temp_root)
            .expect("create temp crate dir");
        let src_dir = temp_dir.path().join("src");
        fs::create_dir_all(&src_dir).expect("create temp crate src dir");

        fs::write(temp_dir.path().join("Cargo.toml"), cargo_toml).expect("write temp Cargo.toml");
        fs::write(src_dir.join("main.rs"), source).expect("write temp main.rs");

        for (relative_path, contents) in extra_files {
            let file_path = temp_dir.path().join(relative_path);
            if let Some(parent) = file_path.parent() {
                fs::create_dir_all(parent).expect("create extra file parent dir");
            }
            fs::write(file_path, contents).expect("write extra test file");
        }

        Self {
            workspace_root,
            temp_dir,
        }
    }

    pub fn path(&self) -> &Path {
        self.temp_dir.path()
    }

    #[allow(dead_code)]
    pub fn cargo_check(&self) -> Output {
        Command::new("cargo")
            .arg("check")
            .arg("--quiet")
            .current_dir(self.path())
            .env("CARGO_TARGET_DIR", self.workspace_root.join("target"))
            .output()
            .expect("run cargo check")
    }

    #[allow(dead_code)]
    pub fn cargo_run(&self) -> Output {
        Command::new("cargo")
            .arg("run")
            .arg("--quiet")
            .current_dir(self.path())
            .env("CARGO_TARGET_DIR", self.workspace_root.join("target"))
            .output()
            .expect("run cargo run")
    }
}