use std::fs;
use std::path::Path;
use std::process;
use crate::format::normalize_line_endings;
pub(crate) fn write_or_check(
path: &Path,
generated: &str,
check_only: bool,
source: &str,
make_target: &str,
) {
if check_only {
check_or_exit(path, generated, source, make_target);
return;
}
if is_current(path, generated) {
return;
}
if let Err(error) = write_file(path, generated) {
eprintln!("error: {error}");
process::exit(1);
}
println!("wrote {}", path.display());
}
pub(crate) fn check_or_exit(path: &Path, generated: &str, source: &str, make_target: &str) {
match fs::read_to_string(path) {
Ok(existing) if same_text(&existing, generated) => return,
Ok(_) => eprintln!("error: {} is stale relative to {source}.", path.display()),
Err(error) => eprintln!("error: cannot read {}: {error}", path.display()),
}
eprintln!("hint: run `make {make_target}` to regenerate.");
process::exit(1);
}
pub(crate) fn check_against(out: &Path, rendered: &str, regenerate: &str) -> i32 {
match fs::read_to_string(out) {
Ok(existing) if same_text(&existing, rendered) => 0,
Ok(_) => {
eprintln!(
"{} is out of date; regenerate with `{regenerate}`",
out.display()
);
1
}
Err(_) => {
eprintln!(
"{} is missing; generate it with `{regenerate}`",
out.display()
);
1
}
}
}
pub(crate) fn is_current(path: &Path, expected: &str) -> bool {
matches!(fs::read_to_string(path), Ok(existing) if same_text(&existing, expected))
}
fn same_text(existing: &str, generated: &str) -> bool {
normalize_line_endings(existing) == normalize_line_endings(generated)
}
pub(crate) fn write_file(path: &Path, body: &str) -> Result<(), String> {
if let Some(parent) = path
.parent()
.filter(|parent| !parent.as_os_str().is_empty())
{
fs::create_dir_all(parent)
.map_err(|error| format!("cannot create {}: {error}", parent.display()))?;
}
fs::write(path, body).map_err(|error| format!("cannot write {}: {error}", path.display()))
}