use crate::error::{AcauaError, Result}; use serde::{Deserialize, Serialize}; use std::process::Command; const LATEST_RELEASE_URL: &str = "https://git.lucasrguerra.dev.br/api/v1/repos/ciberfauna/acaua/releases/latest"; #[derive(Debug, Deserialize)] struct Release { tag_name: String, } #[derive(Debug, Clone, Serialize)] pub struct UpdateStatus { pub current_version: String, pub latest_version: Option, pub update_available: bool, } fn curl_text(url: &str) -> Result { let output = Command::new("curl") .args(["-fsSL", "-H", "User-Agent: acaua-updater", url]) .output() .map_err(|error| AcauaError::CommandFailed { cmd: format!("curl {url}"), detail: error.to_string(), })?; if !output.status.success() { return Err(AcauaError::CommandFailed { cmd: format!("curl {url}"), detail: String::from_utf8_lossy(&output.stderr).into_owned(), }); } Ok(String::from_utf8_lossy(&output.stdout).into_owned()) } pub fn check(current_version: &str) -> Result { let body = match curl_text(LATEST_RELEASE_URL) { Ok(body) => body, Err(_) => { return Ok(UpdateStatus { current_version: current_version.to_string(), latest_version: None, update_available: false, }); } }; let release: Release = serde_json::from_str(&body)?; let latest = release.tag_name.trim_start_matches('v').to_string(); let update_available = latest != current_version; Ok(UpdateStatus { current_version: current_version.to_string(), latest_version: Some(latest), update_available, }) } #[cfg(test)] mod tests { use super::*; #[test] fn parses_latest_release_tag() { let json = r#"{"tag_name": "v0.2.0"}"#; let release: Release = serde_json::from_str(json).unwrap(); assert_eq!(release.tag_name, "v0.2.0"); } }