buster auto update check

This commit is contained in:
dal 2025-04-09 16:24:42 -06:00
parent 9563d4287f
commit c6d0c6b4b1
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
3 changed files with 24 additions and 32 deletions

View File

@ -1,6 +1,6 @@
install: build install: build
mkdir -p $(HOME)/.local/bin mkdir -p $(HOME)/.local/bin
cp cli/target/release/buster-cli $(HOME)/.local/bin/buster-local cp target/release/buster-cli $(HOME)/.local/bin/buster-local
grep -q '/.local/bin' $(HOME)/.zshrc || echo 'export PATH="$$HOME/.local/bin:$$PATH"' >> $(HOME)/.zshrc grep -q '/.local/bin' $(HOME)/.zshrc || echo 'export PATH="$$HOME/.local/bin:$$PATH"' >> $(HOME)/.zshrc
@echo "Run 'source ~/.zshrc' to update your current shell" @echo "Run 'source ~/.zshrc' to update your current shell"

View File

@ -85,8 +85,7 @@ pub struct Args {
async fn main() { async fn main() {
let args = Args::parse(); let args = Args::parse();
// Spawn the update check in the background check_for_updates().await;
tokio::spawn(check_for_updates());
// TODO: All commands should check for an update. // TODO: All commands should check for an update.
let result = match args.cmd { let result = match args.cmd {

View File

@ -4,35 +4,30 @@ use semver::Version;
use serde::Deserialize; use serde::Deserialize;
use std::time::Duration; use std::time::Duration;
const CRATES_IO_API_URL: &str = "https://crates.io/api/v1/crates/"; const GITHUB_API_LATEST_RELEASE_URL: &str =
const CRATE_NAME: &str = env!("CARGO_PKG_NAME"); // Read crate name from Cargo.toml "https://api.github.com/repos/buster-so/buster/releases/latest";
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION"); // Read current version from Cargo.toml const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION"); // Read current version from Cargo.toml
const USER_AGENT: &str = "buster-cli";
// Simplified struct to deserialize only the version field from the crates.io response // Struct to deserialize the tag_name from the GitHub API response
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct CrateInfo { struct GitHubReleaseInfo {
#[serde(rename = "crate")] tag_name: String,
krate: CrateData,
} }
#[derive(Deserialize, Debug)] /// Checks GitHub Releases for a newer version of the CLI.
struct CrateData { /// Prints a message to stderr indicating if an update is available.
max_stable_version: String,
}
/// Checks crates.io for a newer version of the CLI.
/// Prints a message to stderr indicating if an update is available or if the CLI is up-to-date.
/// Fails silently if there's an error checking (e.g., network issues). /// Fails silently if there's an error checking (e.g., network issues).
pub async fn check_for_updates() { pub async fn check_for_updates() {
// Use a short timeout to avoid blocking the CLI for too long
let client = Client::builder() let client = Client::builder()
.timeout(Duration::from_secs(3)) .timeout(Duration::from_secs(3))
.user_agent(USER_AGENT) // Add User-Agent header
.build(); .build();
let client = match client { let client = match client {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(e) => {
// Using eprintln to avoid interfering with potential stdout parsing // Log subtly
eprintln!( eprintln!(
"{}", "{}",
format!("Failed to build HTTP client for update check: {}", e).yellow() format!("Failed to build HTTP client for update check: {}", e).yellow()
@ -41,12 +36,9 @@ pub async fn check_for_updates() {
} }
}; };
let url = format!("{}{}", CRATES_IO_API_URL, CRATE_NAME); let response = match client.get(GITHUB_API_LATEST_RELEASE_URL).send().await {
let response = match client.get(&url).send().await {
Ok(resp) => resp, Ok(resp) => resp,
Err(e) => { Err(e) => {
// Log network errors subtly to stderr
eprintln!("{}", format!("Update check failed: {}", e).yellow()); eprintln!("{}", format!("Update check failed: {}", e).yellow());
return; return;
} }
@ -56,15 +48,16 @@ pub async fn check_for_updates() {
eprintln!( eprintln!(
"{}", "{}",
format!( format!(
"Update check received non-success status: {}", "Update check received non-success status: {}\nURL: {}",
response.status() response.status(),
GITHUB_API_LATEST_RELEASE_URL
) )
.yellow() .yellow()
); );
return; return;
} }
let crate_info = match response.json::<CrateInfo>().await { let release_info = match response.json::<GitHubReleaseInfo>().await {
Ok(info) => info, Ok(info) => info,
Err(e) => { Err(e) => {
eprintln!( eprintln!(
@ -75,7 +68,8 @@ pub async fn check_for_updates() {
} }
}; };
let latest_version_str = &crate_info.krate.max_stable_version; // Remove potential 'v' prefix from tag name
let latest_version_str = release_info.tag_name.trim_start_matches('v');
match ( match (
Version::parse(CURRENT_VERSION), Version::parse(CURRENT_VERSION),
@ -84,7 +78,7 @@ pub async fn check_for_updates() {
(Ok(current), Ok(latest)) => { (Ok(current), Ok(latest)) => {
if latest > current { if latest > current {
eprintln!( eprintln!(
"\n{}", // Add newline for spacing "\n{}",
format!( format!(
"A new version of buster ({}) is available! You have {}.", "A new version of buster ({}) is available! You have {}.",
latest, current latest, current
@ -96,10 +90,8 @@ pub async fn check_for_updates() {
"{}", "{}",
"Please run `buster update` to get the latest version.".red() "Please run `buster update` to get the latest version.".red()
); );
} else {
// Optionally print the up-to-date message, or keep it silent
// eprintln!("{}", "buster is up-to-date.".green());
} }
// No message if up-to-date
} }
(Err(e), _) => { (Err(e), _) => {
eprintln!( eprintln!(
@ -111,8 +103,9 @@ pub async fn check_for_updates() {
eprintln!( eprintln!(
"{}", "{}",
format!( format!(
"Failed to parse latest version ({}): {}", "Failed to parse latest version tag ('{}'): {}",
latest_version_str, e release_info.tag_name, // Show original tag in error
e
) )
.yellow() .yellow()
); );