1pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
11
12pub fn display_version() -> &'static str {
15 std::env::var("TSAFE_CLI_VERSION")
18 .ok()
19 .map(|v| -> &'static str { Box::leak(v.into_boxed_str()) })
20 .unwrap_or(PKG_VERSION)
21}
22
23pub fn check_for_update() -> Option<String> {
29 let base_url = std::env::var("PROGET_BASE_URL").ok()?;
30 if !base_url.starts_with("https://") {
31 return None;
32 }
33 let feed = std::env::var("PROGET_FEED").unwrap_or_else(|_| "tsafe".to_string());
34 let pkg = std::env::var("PROGET_PACKAGE_NAME").unwrap_or_else(|_| "tsafe".to_string());
35 let url = format!("{base_url}/upack/{feed}/versions?packageName={pkg}&count=1");
36
37 let agent = ureq::AgentBuilder::new()
38 .timeout_connect(std::time::Duration::from_secs(3))
39 .timeout(std::time::Duration::from_secs(5))
40 .build();
41
42 let json: serde_json::Value = agent.get(&url).call().ok()?.into_json().ok()?;
43
44 let entry = json.as_array()?.first()?;
47 let latest = entry
48 .get("version")
49 .or_else(|| entry.get("Version"))
50 .and_then(|v| v.as_str())?
51 .to_string();
52
53 if is_newer(&latest, PKG_VERSION) {
54 Some(latest)
55 } else {
56 None
57 }
58}
59
60fn is_newer(candidate: &str, current: &str) -> bool {
62 fn parse(v: &str) -> (u64, u64, u64) {
63 let mut p = v.trim_start_matches('v').split('.');
64 let major: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
65 let minor: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
66 let patch: u64 = p.next().and_then(|s| s.parse().ok()).unwrap_or(0);
67 (major, minor, patch)
68 }
69 parse(candidate) > parse(current)
70}
71
72#[cfg(test)]
73mod tests {
74 use super::is_newer;
75
76 #[test]
77 fn newer_minor_detected() {
78 assert!(is_newer("0.2.0", "0.1.0"));
79 }
80
81 #[test]
82 fn newer_major_detected() {
83 assert!(is_newer("1.0.0", "0.9.9"));
84 }
85
86 #[test]
87 fn newer_patch_detected() {
88 assert!(is_newer("0.1.1", "0.1.0"));
89 }
90
91 #[test]
92 fn same_version_not_newer() {
93 assert!(!is_newer("0.1.0", "0.1.0"));
94 }
95
96 #[test]
97 fn older_version_not_newer() {
98 assert!(!is_newer("0.0.9", "0.1.0"));
99 }
100
101 #[test]
102 fn v_prefix_stripped() {
103 assert!(is_newer("v0.2.0", "0.1.0"));
104 assert!(!is_newer("v0.1.0", "0.1.0"));
105 }
106}