From 1eaeec784f6747d2529951faf4ba98c04383cd4c Mon Sep 17 00:00:00 2001 From: Cyborus Date: Mon, 24 Jun 2024 19:35:54 -0400 Subject: [PATCH] feat: version command and update checker --- Cargo.lock | 7 +++++++ Cargo.toml | 4 ++++ src/main.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 5e21b85..58d05dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,6 +542,7 @@ dependencies = [ "hyper-util", "open", "rand", + "semver", "serde", "serde_json", "sha256", @@ -1590,6 +1591,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.199" diff --git a/Cargo.toml b/Cargo.toml index bd14324..43a6f53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +update-check = ["dep:semver"] + [dependencies] auth-git2 = "0.5.3" base64ct = { version = "1.6.0", features = ["std"] } @@ -20,6 +23,7 @@ hyper = "1.3.1" hyper-util = { version = "0.1.5", features = ["tokio", "server", "http1", "http2"] } open = "5.0.0" rand = "0.8.5" +semver = { version = "1.0.23", optional = true } serde = { version = "1.0.170", features = ["derive"] } serde_json = "1.0.100" sha256 = "1.5.0" diff --git a/src/main.rs b/src/main.rs index f33d71b..4b3f852 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,12 @@ pub enum Command { #[clap(subcommand)] Auth(auth::AuthCommand), Release(release::ReleaseCommand), + Version { + /// Checks for updates + #[clap(long)] + #[cfg(feature = "update-check")] + check: bool, + }, } #[tokio::main] @@ -70,12 +76,62 @@ async fn main() -> eyre::Result<()> { } Command::Auth(subcommand) => subcommand.run(&mut keys, host_name).await?, Command::Release(subcommand) => subcommand.run(&mut keys, host_name).await?, + Command::Version { + #[cfg(feature = "update-check")] + check, + } => { + println!("{}", env!("CARGO_PKG_VERSION")); + #[cfg(feature = "update-check")] + update_msg(check).await?; + } } keys.save().await?; Ok(()) } +#[cfg(feature = "update-check")] +async fn update_msg(check: bool) -> eyre::Result<()> { + use std::cmp::Ordering; + + if check { + let url = url::Url::parse("https://codeberg.org/")?; + let api = forgejo_api::Forgejo::new(forgejo_api::Auth::None, url)?; + + let latest = api + .repo_get_latest_release("Cyborus", "forgejo-cli") + .await?; + let latest_tag = latest + .tag_name + .ok_or_eyre("latest release does not have name")?; + let latest_ver = latest_tag + .strip_prefix("v") + .unwrap_or(&latest_tag) + .parse::()?; + + let current_ver = env!("CARGO_PKG_VERSION").parse::()?; + + match current_ver.cmp(&latest_ver) { + Ordering::Less => { + let latest_url = latest + .html_url + .ok_or_eyre("latest release does not have url")?; + println!("New version available: {latest_ver}"); + println!("Get it at {}", latest_url); + } + Ordering::Equal => { + println!("Up to date!"); + } + Ordering::Greater => { + println!("You are ahead of the latest published version"); + } + } + } else { + println!("Check for a new version with `fj version --check`"); + } + Ok(()) +} + async fn readline(msg: &str) -> eyre::Result { print!("{msg}"); tokio::io::stdout().flush().await?;