vx_core/
version.rs

1//! Version fetching trait and related types
2
3use crate::Result;
4use serde::{Deserialize, Serialize};
5
6/// Trait for fetching version information from external sources
7#[async_trait::async_trait]
8pub trait VersionFetcher: Send + Sync {
9    /// Get the name of the tool this fetcher supports
10    fn tool_name(&self) -> &str;
11
12    /// Fetch available versions for the tool
13    async fn fetch_versions(&self, include_prerelease: bool) -> Result<Vec<VersionInfo>>;
14
15    /// Get the latest stable version
16    async fn get_latest_version(&self) -> Result<Option<VersionInfo>> {
17        let versions = self.fetch_versions(false).await?;
18        Ok(versions.into_iter().next())
19    }
20
21    /// Get the latest version (including prereleases)
22    async fn get_latest_version_including_prerelease(&self) -> Result<Option<VersionInfo>> {
23        let versions = self.fetch_versions(true).await?;
24        Ok(versions.into_iter().next())
25    }
26
27    /// Check if a specific version exists
28    async fn version_exists(&self, version: &str) -> Result<bool> {
29        let versions = self.fetch_versions(true).await?;
30        Ok(versions.iter().any(|v| v.version == version))
31    }
32}
33
34/// Information about a specific version of a tool
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct VersionInfo {
37    /// Version string (e.g., "1.2.3")
38    pub version: String,
39
40    /// Whether this is a prerelease version
41    pub is_prerelease: bool,
42
43    /// Release date in ISO format
44    pub release_date: Option<String>,
45
46    /// Release notes or description
47    pub release_notes: Option<String>,
48
49    /// Download URL for this version
50    pub download_url: Option<String>,
51
52    /// Checksum for verification
53    pub checksum: Option<String>,
54
55    /// File size in bytes
56    pub file_size: Option<u64>,
57
58    /// Additional metadata
59    pub metadata: std::collections::HashMap<String, String>,
60}
61
62impl VersionInfo {
63    /// Create a new VersionInfo with minimal information
64    pub fn new(version: String) -> Self {
65        Self {
66            version,
67            is_prerelease: false,
68            release_date: None,
69            release_notes: None,
70            download_url: None,
71            checksum: None,
72            file_size: None,
73            metadata: std::collections::HashMap::new(),
74        }
75    }
76
77    /// Set prerelease status
78    pub fn with_prerelease(mut self, is_prerelease: bool) -> Self {
79        self.is_prerelease = is_prerelease;
80        self
81    }
82
83    /// Set release date
84    pub fn with_release_date(mut self, date: String) -> Self {
85        self.release_date = Some(date);
86        self
87    }
88
89    /// Set download URL
90    pub fn with_download_url(mut self, url: String) -> Self {
91        self.download_url = Some(url);
92        self
93    }
94
95    /// Set release notes
96    pub fn with_release_notes(mut self, notes: String) -> Self {
97        self.release_notes = Some(notes);
98        self
99    }
100
101    /// Add metadata
102    pub fn with_metadata(mut self, key: String, value: String) -> Self {
103        self.metadata.insert(key, value);
104        self
105    }
106}
107
108/// Version comparison utilities
109pub mod version_utils {
110    use super::VersionInfo;
111
112    /// Sort versions in descending order (latest first)
113    pub fn sort_versions_desc(mut versions: Vec<VersionInfo>) -> Vec<VersionInfo> {
114        versions.sort_by(|a, b| {
115            // Simple string comparison for now
116            // TODO: Implement proper semantic version comparison
117            b.version.cmp(&a.version)
118        });
119        versions
120    }
121
122    /// Filter out prerelease versions
123    pub fn filter_stable_only(versions: Vec<VersionInfo>) -> Vec<VersionInfo> {
124        versions.into_iter().filter(|v| !v.is_prerelease).collect()
125    }
126
127    /// Get the latest N versions
128    pub fn take_latest(versions: Vec<VersionInfo>, count: usize) -> Vec<VersionInfo> {
129        versions.into_iter().take(count).collect()
130    }
131}