use std::path::PathBuf;
pub fn enforce_prebuilt_helpers() -> bool {
matches!(
std::env::var("RAPACE_PREBUILT_HELPERS"),
Ok(v) if v.to_lowercase() == "1" || v.to_lowercase() == "true"
)
}
pub fn find_helper_binary(binary_name: &str) -> Result<PathBuf, String> {
let enforce = enforce_prebuilt_helpers();
let current_exe =
std::env::current_exe().map_err(|e| format!("failed to get current executable: {e}"))?;
let mut search_dir = current_exe
.parent()
.ok_or_else(|| "could not find parent directory".to_string())?;
for _ in 0..3 {
let candidate_path = search_dir.join(binary_name);
if candidate_path.exists() {
return Ok(candidate_path);
}
if let Some(parent) = search_dir.parent() {
search_dir = parent;
} else {
break;
}
}
let profile_dir = match current_exe.parent().and_then(|p| p.parent()) {
Some(dir) => dir.to_path_buf(),
None => {
return Err(format!(
"could not determine target directory from executable path: {current_exe:?}"
));
}
};
let binary_path = profile_dir.join(binary_name);
let error_msg = format!(
"helper binary '{binary_name}' not found. Searched in: {binary_path:?}. \
Build helpers (e.g. 'cargo build --bin {binary_name} -p <package>')"
);
if enforce {
panic!(
"RAPACE_PREBUILT_HELPERS is set: {error_msg}\n\
To build helpers manually: cargo xtask test --no-run\n\
Then use: RAPACE_PREBUILT_HELPERS=1 cargo test"
);
}
Err(error_msg)
}
#[cfg(test)]
mod tests {
use super::*;
fn env_lock() -> &'static std::sync::Mutex<()> {
static LOCK: std::sync::OnceLock<std::sync::Mutex<()>> = std::sync::OnceLock::new();
LOCK.get_or_init(|| std::sync::Mutex::new(()))
}
fn get_prebuilt_helpers_var() -> Option<std::ffi::OsString> {
std::env::var_os("RAPACE_PREBUILT_HELPERS")
}
fn set_prebuilt_helpers_var(value: &str) {
unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", value) };
}
fn remove_prebuilt_helpers_var() {
unsafe { std::env::remove_var("RAPACE_PREBUILT_HELPERS") };
}
#[test]
fn enforce_prebuilt_helpers_off_by_default() {
let _guard = env_lock().lock().unwrap();
let prev = get_prebuilt_helpers_var();
remove_prebuilt_helpers_var();
assert!(!enforce_prebuilt_helpers());
match prev {
Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
None => remove_prebuilt_helpers_var(),
}
}
#[test]
fn enforce_prebuilt_helpers_true() {
let _guard = env_lock().lock().unwrap();
let prev = get_prebuilt_helpers_var();
set_prebuilt_helpers_var("true");
assert!(enforce_prebuilt_helpers());
match prev {
Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
None => remove_prebuilt_helpers_var(),
}
}
#[test]
fn enforce_prebuilt_helpers_1() {
let _guard = env_lock().lock().unwrap();
let prev = get_prebuilt_helpers_var();
set_prebuilt_helpers_var("1");
assert!(enforce_prebuilt_helpers());
match prev {
Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
None => remove_prebuilt_helpers_var(),
}
}
#[test]
fn enforce_prebuilt_helpers_false() {
let _guard = env_lock().lock().unwrap();
let prev = get_prebuilt_helpers_var();
set_prebuilt_helpers_var("false");
assert!(!enforce_prebuilt_helpers());
match prev {
Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
None => remove_prebuilt_helpers_var(),
}
}
#[test]
fn find_helper_binary_not_found_not_enforced() {
let _guard = env_lock().lock().unwrap();
let prev = get_prebuilt_helpers_var();
remove_prebuilt_helpers_var();
let result = find_helper_binary("nonexistent-binary");
assert!(result.is_err());
match prev {
Some(v) => unsafe { std::env::set_var("RAPACE_PREBUILT_HELPERS", v) },
None => remove_prebuilt_helpers_var(),
}
}
}