use std::path::{Path, PathBuf}; use std::process::exit; use colored::Colorize; pub fn workspace_dir() -> PathBuf { let output = std::process::Command::new(env!("CARGO")) .arg("locate-project") .arg("--workspace") .arg("--message-format=plain") .output() .unwrap() .stdout; let cargo_path = Path::new(std::str::from_utf8(&output).unwrap().trim()); cargo_path.parent().unwrap().to_path_buf() } pub fn cargo(cmd: String) { println!("{} cargo {}", "[cargo]".bold().cyan(), cmd); let mut output = std::process::Command::new(env!("CARGO")); for (key, _) in std::env::vars_os() { let Some(key) = key.to_str() else { continue }; if SANITIZED_ENV_VARS.matches(key) { output.env_remove(key); } } for command in cmd.split(" ") { output.arg(command); } let output = output.spawn().unwrap().wait().unwrap(); if !output.success() { println!("{}", "============ TASK FAILED".bold().red()); exit(1); } } #[derive(Debug)] struct SanitizedEnvVars { // At the moment we only ban some prefixes, but we may also want to ban env // vars by exact name in the future. prefixes: &'static [&'static str], } impl SanitizedEnvVars { const fn new() -> Self { // Remove many of the environment variables set in // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts. // This is done to avoid recompilation with crates like ring between // `cargo clippy` and `cargo xtask clippy`. (This is really a bug in // both ring's build script and in Cargo.) // // The current list is informed by looking at ring's build script, so // it's not guaranteed to be exhaustive and it may need to grow over // time. let prefixes = &["CARGO_PKG_", "CARGO_MANIFEST_", "CARGO_CFG_"]; Self { prefixes } } fn matches(&self, key: &str) -> bool { self.prefixes.iter().any(|prefix| key.starts_with(prefix)) } } static SANITIZED_ENV_VARS: SanitizedEnvVars = SanitizedEnvVars::new(); pub fn wasmopt(cmd: String) { println!("{} wasm-opt {}", "[wasm-opt]".bold().cyan(), cmd); let mut output = std::process::Command::new("wasm-opt"); for command in cmd.split(" ") { output.arg(command); } let output = output.spawn().unwrap().wait().unwrap(); if !output.success() { println!("{}", "============ TASK FAILED".bold().red()); exit(1); } } pub fn wbg(cmd: String) { println!("{} wasm-bindgen {}", "[wasm-bindgen]".bold().cyan(), cmd); let mut output = std::process::Command::new("wasm-bindgen"); for command in cmd.split(" ") { output.arg(command); } let output = output.spawn().unwrap().wait().unwrap(); if !output.success() { println!("{}", "============ TASK FAILED".bold().red()); exit(1); } }