#[cfg(unix)]
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::process::Command;
pub fn run(args: &[String]) -> ! {
let Some((binary, rest)) = args.split_first() else {
eprintln!("cargo-affected runner-shim: missing test binary argument");
std::process::exit(2);
};
if let (Ok(binary_id), Ok(test_name)) = (
std::env::var("NEXTEST_BINARY_ID"),
std::env::var("NEXTEST_TEST_NAME"),
) {
let base = std::env::var("CARGO_AFFECTED_PROFRAW_BASE").unwrap_or_else(|_| {
eprintln!("cargo-affected runner-shim: CARGO_AFFECTED_PROFRAW_BASE not set");
std::process::exit(2);
});
let dir = Path::new(&base)
.join(sanitize(&binary_id))
.join(sanitize(&test_name));
if let Err(e) = std::fs::create_dir_all(&dir) {
eprintln!(
"cargo-affected runner-shim: failed to create {}: {e}",
dir.display()
);
std::process::exit(2);
}
let _ = std::fs::write(
dir.join("meta"),
format!("{test_name}\n{binary}\n{binary_id}\n"),
);
std::env::set_var("LLVM_PROFILE_FILE", dir.join("%p-%m.profraw"));
}
exec_or_spawn(binary, rest);
}
#[cfg(unix)]
fn exec_or_spawn(binary: &str, rest: &[String]) -> ! {
let err = Command::new(binary).args(rest).exec();
eprintln!(
"cargo-affected runner-shim: exec {} failed: {err}",
binary
);
std::process::exit(127);
}
#[cfg(not(unix))]
fn exec_or_spawn(binary: &str, rest: &[String]) -> ! {
let status = match Command::new(binary).args(rest).status() {
Ok(s) => s,
Err(e) => {
eprintln!(
"cargo-affected runner-shim: spawn {} failed: {e}",
binary
);
std::process::exit(127);
}
};
std::process::exit(status.code().unwrap_or(127));
}
pub fn sanitize(name: &str) -> String {
let mut out = String::with_capacity(name.len());
for c in name.chars() {
if c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.' {
out.push(c);
} else {
out.push('_');
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanitize_passthrough() {
assert_eq!(sanitize("plain_name"), "plain_name");
assert_eq!(sanitize("dotted.name-1"), "dotted.name-1");
}
#[test]
fn sanitize_replaces_hostile_chars() {
assert_eq!(sanitize("math::tests::test_add"), "math__tests__test_add");
assert_eq!(sanitize("mock-stub::builds"), "mock-stub__builds");
assert_eq!(sanitize("a/b"), "a_b");
assert_eq!(sanitize("a\\b"), "a_b");
assert_eq!(sanitize("a b"), "a_b");
}
}