use std::path::Path;
use std::process::Command;
use crate::error::{Error, Result};
use super::semantic::Difference;
pub fn is_available(program: &str) -> bool {
std::process::Command::new(program)
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
pub fn run(program: &str, path: &Path, lo: i32, hi: i32) -> Result<Vec<String>> {
debug_assert!(path.is_absolute(), "zdump needs an absolute path");
let path_str = path.to_str().ok_or_else(|| {
Error::message("compiled zone path is not valid UTF-8 (cannot pass to zdump)")
})?;
let output = Command::new(program)
.arg("-v")
.arg("-c")
.arg(format!("{lo},{hi}"))
.arg(path_str)
.output()
.map_err(|e| Error::message(format!("failed to run {program:?}: {e}")))?;
if !output.status.success() {
return Err(Error::message(format!(
"{program} failed for {path_str}: {}",
String::from_utf8_lossy(&output.stderr).trim()
)));
}
let stdout = String::from_utf8_lossy(&output.stdout);
let normalised = stdout
.lines()
.map(|line| normalise(line, path_str))
.collect();
Ok(normalised)
}
fn normalise(line: &str, path: &str) -> String {
line.strip_prefix(path)
.unwrap_or(line)
.trim_start()
.to_string()
}
pub fn diff(ours: &[String], theirs: &[String]) -> Vec<Difference> {
let mut diffs = Vec::new();
if ours.len() != theirs.len() {
diffs.push(Difference {
what: "zdump line count".into(),
ours: ours.len().to_string(),
theirs: theirs.len().to_string(),
});
}
for (i, (a, b)) in ours.iter().zip(theirs).enumerate() {
if a != b {
diffs.push(Difference {
what: format!("zdump line {i}"),
ours: a.clone(),
theirs: b.clone(),
});
}
}
diffs
}