use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;
pub fn fake_tool(dir: &Path, name: &str, body: &str) -> (PathBuf, PathBuf) {
let calls = dir.join(format!("{name}.calls"));
let script = dir.join(name);
write_script(
&script,
&format!(
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> {}\ncase \"$*\" in\n{body}\nesac\n",
calls.display()
),
);
std::fs::remove_file(&calls).ok();
(script, calls)
}
pub fn calls(log: &Path) -> Vec<String> {
std::fs::read_to_string(log)
.unwrap_or_default()
.lines()
.map(str::to_owned)
.collect()
}
pub fn write_script(path: &Path, body: &str) {
use std::os::unix::fs::PermissionsExt as _;
std::fs::write(path, body).unwrap();
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755)).unwrap();
let deadline = std::time::Instant::now() + Duration::from_secs(5);
loop {
match Command::new(path).output() {
Err(error) if error.kind() == std::io::ErrorKind::ExecutableFileBusy => {
assert!(
std::time::Instant::now() < deadline,
"{} stayed busy for 5s",
path.display()
);
std::thread::sleep(Duration::from_millis(5));
}
other => {
other.unwrap();
return;
}
}
}
}