use std::process::Child;
pub(crate) struct KeepAwake(Option<Child>);
#[cfg(target_os = "macos")]
pub(crate) fn keep_awake() -> KeepAwake {
use std::process::{Command, Stdio};
let child = Command::new("/usr/bin/caffeinate")
.args(["-i", "-w", &std::process::id().to_string()])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.ok();
KeepAwake(child)
}
#[cfg(not(target_os = "macos"))]
pub(crate) fn keep_awake() -> KeepAwake {
KeepAwake(None)
}
impl Drop for KeepAwake {
fn drop(&mut self) {
if let Some(child) = &mut self.0 {
let _ = child.kill();
let _ = child.wait();
}
}
}
#[cfg(all(test, target_os = "macos"))]
mod tests {
use super::*;
fn alive(pid: u32) -> bool {
std::process::Command::new("/bin/kill")
.args(["-0", &pid.to_string()])
.output()
.is_ok_and(|output| output.status.success())
}
#[test]
fn the_assertion_is_held_while_the_guard_lives_and_released_with_it() {
let guard = keep_awake();
let pid = guard.0.as_ref().expect("caffeinate is part of macOS").id();
assert!(alive(pid), "caffeinate should be running");
drop(guard);
assert!(!alive(pid), "caffeinate outlived its guard");
}
}