use crate::progress::{is_stdin_cancel_line, STDIN_CANCEL_LINE};
use std::io;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
pub fn cancel_cache_dir() -> io::Result<PathBuf> {
Ok(user_cache_dir()?.join("litho"))
}
fn user_cache_dir() -> io::Result<PathBuf> {
#[cfg(windows)]
{
if let Some(local) = std::env::var_os("LOCALAPPDATA") {
return Ok(PathBuf::from(local));
}
if let Some(home) = std::env::var_os("USERPROFILE") {
return Ok(PathBuf::from(home).join("AppData").join("Local"));
}
return Ok(std::env::temp_dir());
}
#[cfg(not(windows))]
{
if let Some(xdg) = std::env::var_os("XDG_CACHE_HOME") {
return Ok(PathBuf::from(xdg));
}
let home = std::env::var_os("HOME")
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "HOME is not set"))?;
Ok(PathBuf::from(home).join(".cache"))
}
}
pub fn create_cancel_file() -> io::Result<PathBuf> {
let dir = cancel_cache_dir()?;
std::fs::create_dir_all(&dir)?;
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
let path = dir.join(format!("cancel-{}-{nanos}.flag", std::process::id()));
init_cancel_file(&path)?;
Ok(path)
}
pub fn init_cancel_file(path: &Path) -> io::Result<()> {
std::fs::write(path, "")?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o644))?;
}
Ok(())
}
pub fn request_cancel_via_file(path: &Path) -> io::Result<()> {
std::fs::write(path, format!("{STDIN_CANCEL_LINE}\n"))
}
pub fn cancel_requested_in_file(path: &Path) -> bool {
std::fs::read_to_string(path)
.ok()
.is_some_and(|contents| is_stdin_cancel_line(&contents))
}
pub fn remove_cancel_file(path: &Path) {
let _ = std::fs::remove_file(path);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cancel_file_marker_round_trip() {
let path = std::env::temp_dir().join(format!(
"litho-cancel-lib-test-{}-{}.flag",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
));
init_cancel_file(&path).unwrap();
assert!(!cancel_requested_in_file(&path));
request_cancel_via_file(&path).unwrap();
assert!(cancel_requested_in_file(&path));
remove_cancel_file(&path);
}
}