diff --git a/crates/tower-cmd/src/lib.rs b/crates/tower-cmd/src/lib.rs index 483f7c48..cd4fcbda 100644 --- a/crates/tower-cmd/src/lib.rs +++ b/crates/tower-cmd/src/lib.rs @@ -85,8 +85,10 @@ impl App { if let Some(latest) = Self::check_latest_version().await { let current = tower_version::current_version(); - if current != latest { - output::write_update_message(&latest, ¤t); + if tower_version::is_older_version(current, &latest) { + output::write_update_available_message(&latest, current); + } else if tower_version::is_newer_version(current, &latest) { + output::write_dev_version_message(current, &latest); } } diff --git a/crates/tower-cmd/src/output.rs b/crates/tower-cmd/src/output.rs index fc3b7bb2..272a31da 100644 --- a/crates/tower-cmd/src/output.rs +++ b/crates/tower-cmd/src/output.rs @@ -501,7 +501,7 @@ pub fn spinner(msg: &str) -> Spinner { Spinner::new(msg.into()) } -pub fn write_update_message(latest: &str, current: &str) { +pub fn write_update_available_message(latest: &str, current: &str) { let line = format!( "{}\n{}\n", format!( @@ -517,6 +517,20 @@ pub fn write_update_message(latest: &str, current: &str) { io::stderr().write_all(line.as_bytes()).unwrap(); } +pub fn write_dev_version_message(current: &str, latest: &str) { + let line = format!( + "{}\n", + format!( + "Running dev version {} (latest published: {})", + current, latest + ) + .dimmed() + ); + + use std::io::{self, Write}; + io::stderr().write_all(line.as_bytes()).unwrap(); +} + /// newline just outputs a newline. This is useful when you have a very specific formatting you /// want to maintain and you don't want to use println!. pub fn newline() { diff --git a/crates/tower-version/src/lib.rs b/crates/tower-version/src/lib.rs index 3deb1449..4d8202c6 100644 --- a/crates/tower-version/src/lib.rs +++ b/crates/tower-version/src/lib.rs @@ -42,3 +42,39 @@ pub async fn check_latest_version() -> Result> { } Ok(None) } + +fn parse_version(v: &str) -> Option<(u32, u32, u32)> { + let parts: Vec<_> = v.split('.').filter_map(|p| p.parse::().ok()).collect(); + (parts.len() == 3).then(|| (parts[0], parts[1], parts[2])) +} + +pub fn is_older_version(current: &str, latest: &str) -> bool { + matches!((parse_version(current), parse_version(latest)), (Some(c), Some(l)) if c < l) +} + +pub fn is_newer_version(current: &str, latest: &str) -> bool { + matches!((parse_version(current), parse_version(latest)), (Some(c), Some(l)) if c > l) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_current_version_equal() { + assert!(!is_older_version("0.3.39", "0.3.39")); + assert!(!is_newer_version("0.3.39", "0.3.39")); + } + + #[test] + fn test_older_version() { + assert!(is_older_version("0.3.38", "0.3.39")); + assert!(!is_newer_version("0.3.38", "0.3.39")); + } + + #[test] + fn test_newer_version() { + assert!(!is_older_version("0.3.40", "0.3.39")); + assert!(is_newer_version("0.3.40", "0.3.39")); + } +}