pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn display_version() -> &'static str {
std::env::var("TSAFE_CLI_VERSION")
.ok()
.map(|v| -> &'static str { Box::leak(v.into_boxed_str()) })
.unwrap_or(PKG_VERSION)
}
pub fn check_for_update() -> Option<String> {
let base_url = std::env::var("PROGET_BASE_URL").ok()?;
if !base_url.starts_with("https://") {
return None;
}
let feed = std::env::var("PROGET_FEED").unwrap_or_else(|_| "tsafe".to_string());
let pkg = std::env::var("PROGET_PACKAGE_NAME").unwrap_or_else(|_| "tsafe".to_string());
let url = format!("{base_url}/upack/{feed}/versions?packageName={pkg}&count=1");
let agent = ureq::AgentBuilder::new()
.timeout_connect(std::time::Duration::from_secs(3))
.timeout(std::time::Duration::from_secs(5))
.build();
let json: serde_json::Value = agent.get(&url).call().ok()?.into_json().ok()?;
let entry = json.as_array()?.first()?;
let latest = entry
.get("version")
.or_else(|| entry.get("Version"))
.and_then(|v| v.as_str())?
.to_string();
if is_newer(&latest, PKG_VERSION) {
Some(latest)
} else {
None
}
}
fn is_newer(candidate: &str, current: &str) -> bool {
fn parse(v: &str) -> (u64, u64, u64) {
let mut p = v.trim_start_matches('v').split('.');
let major: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
let minor: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
let patch: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
(major, minor, patch)
}
parse(candidate) > parse(current)
}
#[cfg(test)]
mod tests {
use super::is_newer;
#[test]
fn newer_minor_detected() {
assert!(is_newer("0.2.0", "0.1.0"));
}
#[test]
fn newer_major_detected() {
assert!(is_newer("1.0.0", "0.9.9"));
}
#[test]
fn newer_patch_detected() {
assert!(is_newer("0.1.1", "0.1.0"));
}
#[test]
fn same_version_not_newer() {
assert!(!is_newer("0.1.0", "0.1.0"));
}
#[test]
fn older_version_not_newer() {
assert!(!is_newer("0.0.9", "0.1.0"));
}
#[test]
fn v_prefix_stripped() {
assert!(is_newer("v0.2.0", "0.1.0"));
assert!(!is_newer("v0.1.0", "0.1.0"));
}
}