use std::fs;
use std::path::Path;
use anyhow::Result;
use openmoat_hosts::OwnedFile;
use super::{HOOK_BACKUP, HookState, HostConfig, Outcome};
use crate::home::{Home, write_private};
pub fn text(file: &OwnedFile, binary: &Path) -> Result<String> {
Ok(file.text(&binary.to_string_lossy())?)
}
pub fn install(
home: &Home,
config: &HostConfig,
file: &OwnedFile,
binary: &Path,
dry_run: bool,
) -> Result<Outcome> {
let path = &config.settings_path;
let wanted = text(file, binary)?;
let current = fs::read_to_string(path).ok();
let outcome = match ¤t {
Some(text) if *text == wanted => Outcome::Unchanged,
Some(text) if file.is_ours(text) => Outcome::Updated,
_ => Outcome::Installed,
};
if outcome == Outcome::Unchanged || dry_run {
return Ok(outcome);
}
if current.as_deref().is_some_and(|text| !file.is_ours(text)) {
super::back_up(home, path, HOOK_BACKUP)?;
}
write_private(path, wanted.as_bytes())?;
Ok(outcome)
}
pub fn render(file: &OwnedFile, binary: &Path, current: &str) -> Result<Option<String>> {
let wanted = text(file, binary)?;
Ok((wanted != current).then_some(wanted))
}
pub fn state(config: &HostConfig, file: &OwnedFile, binary: &Path) -> HookState {
let current = match fs::read_to_string(&config.settings_path) {
Ok(text) => text,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return HookState::Missing,
Err(e) => {
return HookState::Unreadable(format!(
"reading {}: {e}",
config.settings_path.display()
));
}
};
if text(file, binary).is_ok_and(|wanted| wanted == current) {
return HookState::Installed;
}
if !file.is_ours(¤t) {
return HookState::Missing;
}
HookState::Stale {
command: file.binary(¤t).unwrap_or_else(|| "?".to_owned()),
}
}
#[cfg(test)]
mod tests;