use std::fs::OpenOptions;
use std::io::ErrorKind;
use std::path::Path;
use anyhow::Context;
pub fn rewrite(dir: &Path, name: &str, change: impl FnOnce(&str) -> String) -> anyhow::Result<()> {
std::fs::create_dir_all(dir).with_context(|| format!("creating {}", dir.display()))?;
let lock_path = dir.join(format!("{name}.lock"));
let lock = OpenOptions::new()
.write(true)
.create(true)
.truncate(false)
.open(&lock_path)
.with_context(|| format!("opening {}", lock_path.display()))?;
lock.lock()
.with_context(|| format!("locking {}", lock_path.display()))?;
let file = dir.join(name);
let text = match std::fs::read_to_string(&file) {
Ok(t) => t,
Err(e) if e.kind() == ErrorKind::NotFound => String::new(),
Err(e) => return Err(e).with_context(|| format!("reading {}", file.display())),
};
let tmp = dir.join(format!("{name}.tmp"));
std::fs::write(&tmp, change(&text)).with_context(|| format!("writing {}", tmp.display()))?;
std::fs::rename(&tmp, &file).with_context(|| format!("writing {}", file.display()))?;
Ok(())
}