From 816f9241848c13834dc3bb4cb618c998e1a2d7f9 Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 13:30:21 +0100 Subject: [PATCH 1/6] Sort version output and show upgrade version --- crates/update/src/cli/install.rs | 12 ++++++ crates/update/src/cli/list.rs | 63 ++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/crates/update/src/cli/install.rs b/crates/update/src/cli/install.rs index bc04ab2b3ef..5ab64af9883 100644 --- a/crates/update/src/cli/install.rs +++ b/crates/update/src/cli/install.rs @@ -152,6 +152,18 @@ impl ArtifactType { } } +pub(super) async fn fetch_latest_version(client: &reqwest::Client) -> anyhow::Result { + let url = format!("{}/latest", releases_url()); + let release: Release = client + .get(url) + .send() + .await? + .error_for_status()? + .json() + .await?; + release.version().context("Could not parse latest version number") +} + pub(super) async fn available_releases(client: &reqwest::Client) -> anyhow::Result> { let url = releases_url(); let releases: Vec = client.get(url).send().await?.json().await?; diff --git a/crates/update/src/cli/list.rs b/crates/update/src/cli/list.rs index 25b10458e2a..002e9167050 100644 --- a/crates/update/src/cli/list.rs +++ b/crates/update/src/cli/list.rs @@ -36,19 +36,74 @@ impl List { Some(file_name.to_string()) } }; + let versions = if self.all { let client = super::reqwest_client()?; super::tokio_block_on(super::install::available_releases(&client))?? } else { paths.cli_bin_dir.installed_versions()? }; + + // Sort versions using semver ordering. Versions that fail to parse are + // placed at the end in their original (alphabetical) order. + let mut parsed: Vec<(semver::Version, String)> = Vec::new(); + let mut unparsed: Vec = Vec::new(); for ver in versions { - print!("{ver}"); - if Some(&ver) == current.as_ref() { - print!(" (current)"); + match semver::Version::parse(&ver) { + Ok(sv) => parsed.push((sv, ver)), + Err(_) => unparsed.push(ver), } - println!(); } + parsed.sort_by(|(a, _), (b, _)| b.cmp(a)); + + let sorted_versions: Vec = parsed.into_iter().map(|(_, s)| s).chain(unparsed).collect(); + + // Check for a newer version available on GitHub. + let latest = if !self.all { + let client = super::reqwest_client().ok(); + client.and_then(|c| { + super::tokio_block_on(super::install::fetch_latest_version(&c)) + .ok() + .and_then(|r| r.ok()) + }) + } else { + None + }; + + // Determine whether the latest version is newer than any installed version. + let newest_installed = sorted_versions.last().and_then(|v| semver::Version::parse(v).ok()); + + let show_latest = match (&latest, &newest_installed) { + (Some(lat), Some(cur)) if lat > cur => Some(lat.to_string()), + _ => None, + }; + + for ver in &sorted_versions { + let is_current = Some(ver) == current.as_ref(); + + // If this is the current version and there's a newer version + // available, print the newer version first. + if is_current { + if let Some(ref new_ver) = show_latest { + println!("{} {}", new_ver, "(available - run `spacetime version upgrade`)"); + } + } + + if is_current { + println!("{} {}", ver, "(current)"); + } else { + println!("{ver}"); + } + } + + // If there's no current version set but a latest is available, + // still show it at the end. + if current.is_none() { + if let Some(ref new_ver) = show_latest { + println!("{} {}", new_ver, "(available - run `spacetime version upgrade`)"); + } + } + Ok(()) } } From 1ee294d8df04eb267d457c1699737e3831150adc Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 14:52:59 +0100 Subject: [PATCH 2/6] simplify comment --- crates/update/src/cli/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/update/src/cli/list.rs b/crates/update/src/cli/list.rs index 002e9167050..6ceee7f84ac 100644 --- a/crates/update/src/cli/list.rs +++ b/crates/update/src/cli/list.rs @@ -45,7 +45,7 @@ impl List { }; // Sort versions using semver ordering. Versions that fail to parse are - // placed at the end in their original (alphabetical) order. + // placed at the end in alphabetical order. let mut parsed: Vec<(semver::Version, String)> = Vec::new(); let mut unparsed: Vec = Vec::new(); for ver in versions { From 671fddf9bea0222f687c687aa932d02e16f9ab34 Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 14:58:06 +0100 Subject: [PATCH 3/6] Print available version first if current is not set --- crates/update/src/cli/list.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/update/src/cli/list.rs b/crates/update/src/cli/list.rs index 6ceee7f84ac..7ee8c4ddf5b 100644 --- a/crates/update/src/cli/list.rs +++ b/crates/update/src/cli/list.rs @@ -78,6 +78,14 @@ impl List { _ => None, }; + // If there's no current version set but a latest is available, + // still show it first. + if current.is_none() { + if let Some(ref new_ver) = show_latest { + println!("{} {}", new_ver, "(available - run `spacetime version upgrade`)"); + } + } + for ver in &sorted_versions { let is_current = Some(ver) == current.as_ref(); @@ -96,14 +104,6 @@ impl List { } } - // If there's no current version set but a latest is available, - // still show it at the end. - if current.is_none() { - if let Some(ref new_ver) = show_latest { - println!("{} {}", new_ver, "(available - run `spacetime version upgrade`)"); - } - } - Ok(()) } } From c7e4a0f1e7be9f56a553b2078dd7db0bd5501805 Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 15:00:23 +0100 Subject: [PATCH 4/6] Fix getting latest installed --- crates/update/src/cli/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/update/src/cli/list.rs b/crates/update/src/cli/list.rs index 7ee8c4ddf5b..60eefa670ad 100644 --- a/crates/update/src/cli/list.rs +++ b/crates/update/src/cli/list.rs @@ -71,7 +71,7 @@ impl List { }; // Determine whether the latest version is newer than any installed version. - let newest_installed = sorted_versions.last().and_then(|v| semver::Version::parse(v).ok()); + let newest_installed = sorted_versions.first().and_then(|v| semver::Version::parse(v).ok()); let show_latest = match (&latest, &newest_installed) { (Some(lat), Some(cur)) if lat > cur => Some(lat.to_string()), From f8c6f6a350cf1a8032e8bdbde9a56b63e79ac9e4 Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 15:37:58 +0100 Subject: [PATCH 5/6] Update comment --- crates/update/src/cli/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/update/src/cli/list.rs b/crates/update/src/cli/list.rs index 60eefa670ad..9c569d30b5d 100644 --- a/crates/update/src/cli/list.rs +++ b/crates/update/src/cli/list.rs @@ -45,7 +45,7 @@ impl List { }; // Sort versions using semver ordering. Versions that fail to parse are - // placed at the end in alphabetical order. + // placed at the end in their original listed. let mut parsed: Vec<(semver::Version, String)> = Vec::new(); let mut unparsed: Vec = Vec::new(); for ver in versions { From b973d2c90c20060e7d804c00436d9d15dc7f6768 Mon Sep 17 00:00:00 2001 From: Alessandro Asoni Date: Tue, 10 Feb 2026 19:42:34 +0100 Subject: [PATCH 6/6] Format --- crates/update/src/cli/install.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/update/src/cli/install.rs b/crates/update/src/cli/install.rs index 5ab64af9883..dafa4a23b60 100644 --- a/crates/update/src/cli/install.rs +++ b/crates/update/src/cli/install.rs @@ -154,13 +154,7 @@ impl ArtifactType { pub(super) async fn fetch_latest_version(client: &reqwest::Client) -> anyhow::Result { let url = format!("{}/latest", releases_url()); - let release: Release = client - .get(url) - .send() - .await? - .error_for_status()? - .json() - .await?; + let release: Release = client.get(url).send().await?.error_for_status()?.json().await?; release.version().context("Could not parse latest version number") }