use std::path::PathBuf;
pub const FORMAT: &str = "amont-skew-v1";
const MARKER: &str = "amont-skew";
pub fn absorb_newer_hook(hook: &str) -> i32 {
let version = env!("CARGO_PKG_VERSION");
if !already_warned(version) {
eprintln!(
"amont: the {hook} shim is newer than this binary ({version}) — the hook did nothing.\n\
Upgrade amont to match the shims (said once per binary version)."
);
remember(version);
}
0
}
fn marker_path() -> Option<PathBuf> {
let dir = crate::git::stdout(&["rev-parse", "--git-dir"])?;
Some(std::path::Path::new(&dir).join(MARKER))
}
fn already_warned(version: &str) -> bool {
let Some(path) = marker_path() else {
return false; };
let Ok(body) = std::fs::read_to_string(&path) else {
return false;
};
let mut lines = body.lines();
lines.next() == Some(FORMAT) && lines.next() == Some(version)
}
fn remember(version: &str) {
let Some(path) = marker_path() else { return };
let _ = std::fs::write(&path, format!("{FORMAT}\n{version}\n"));
}
pub fn announce_minimum() {
let Some(want) = crate::config::string_value("amont.minVersion") else {
return;
};
let Some(min) = parse_version(&want) else {
crate::config::complain(
"amont.minVersion",
"not a version (want x.y.z)",
"no minimum",
);
return;
};
let have = env!("CARGO_PKG_VERSION");
let running = parse_version(have).expect("own version parses");
if running < min {
println!(
"{} this repository asks for amont {} or newer — this binary is {have}. Upgrade amont.",
crate::ui::warning_sign(),
crate::ui::highlight(want.trim()),
);
}
}
fn parse_version(s: &str) -> Option<(u64, u64, u64)> {
let mut parts = s.trim().splitn(3, '.');
let major = parts.next()?.parse().ok()?;
let minor = match parts.next() {
Some(p) => p.parse().ok()?,
None => 0,
};
let patch = match parts.next() {
Some(p) => p.parse().ok()?,
None => 0,
};
Some((major, minor, patch))
}
pub fn forget() -> bool {
marker_path().is_some_and(|path| std::fs::remove_file(&path).is_ok())
}
pub fn forget_in(repo: &std::path::Path) -> bool {
let Some(dir) = crate::git::stdout_in(repo, &["rev-parse", "--absolute-git-dir"]) else {
return false;
};
std::fs::remove_file(std::path::Path::new(&dir).join(MARKER)).is_ok()
}
#[cfg(test)]
mod tests {
use super::parse_version;
#[test]
fn short_and_full_spellings_agree() {
assert_eq!(parse_version("1.9"), parse_version("1.9.0"));
assert_eq!(parse_version(" 1.9.3 "), Some((1, 9, 3)));
assert_eq!(parse_version("2"), Some((2, 0, 0)));
}
#[test]
fn ordering_is_numeric_not_lexical() {
assert!(parse_version("1.10.0").unwrap() > parse_version("1.9.0").unwrap());
}
#[test]
fn garbage_is_not_a_version() {
for bad in ["banana", "1.x", "", "v1.2.3", "1.2.3-rc1"] {
assert_eq!(parse_version(bad), None, "{bad:?}");
}
}
}