Skip to main content

bytes_radar/net/providers/
archive.rs

1use crate::net::traits::{GitProvider, ParsedRepository, ProviderConfig};
2use async_trait::async_trait;
3use reqwest::Client;
4use std::collections::HashMap;
5
6pub struct ArchiveProvider {
7    credentials: HashMap<String, String>,
8}
9
10impl ArchiveProvider {
11    pub fn new() -> Self {
12        Self {
13            credentials: HashMap::new(),
14        }
15    }
16}
17
18#[async_trait]
19impl GitProvider for ArchiveProvider {
20    fn name(&self) -> &'static str {
21        "archive"
22    }
23
24    fn can_handle(&self, url: &str) -> bool {
25        url.ends_with(".tar.gz")
26            || url.ends_with(".tgz")
27            || url.ends_with(".tar.bz2")
28            || url.ends_with(".tar.xz")
29            || url.ends_with(".zip")
30            || url.contains("/archive/")
31            || url.contains("/tarball/")
32            || url.contains("/zipball/")
33    }
34
35    fn parse_url(&self, url: &str) -> Option<ParsedRepository> {
36        if !self.can_handle(url) {
37            return None;
38        }
39
40        let filename = url.split('/').next_back()?;
41        let name = self.extract_name_from_filename(filename);
42
43        Some(
44            ParsedRepository::new("archive".to_string(), name.clone())
45                .with_host(self.extract_host_from_url(url)),
46        )
47    }
48
49    fn build_download_urls(&self, _parsed: &ParsedRepository) -> Vec<String> {
50        vec![]
51    }
52
53    async fn get_default_branch(
54        &self,
55        _client: &Client,
56        _parsed: &ParsedRepository,
57    ) -> Option<String> {
58        None
59    }
60
61    fn apply_config(&mut self, config: &ProviderConfig) {
62        self.credentials = config.credentials.clone();
63    }
64
65    fn get_project_name(&self, url: &str) -> String {
66        if let Some(filename) = url.split('/').next_back() {
67            return self.extract_name_from_filename(filename);
68        }
69
70        "archive-project".to_string()
71    }
72}
73
74impl ArchiveProvider {
75    fn extract_name_from_filename(&self, filename: &str) -> String {
76        let name = if filename.ends_with(".tar.gz") {
77            filename.trim_end_matches(".tar.gz")
78        } else if filename.ends_with(".tgz") {
79            filename.trim_end_matches(".tgz")
80        } else if filename.ends_with(".tar.bz2") {
81            filename.trim_end_matches(".tar.bz2")
82        } else if filename.ends_with(".tar.xz") {
83            filename.trim_end_matches(".tar.xz")
84        } else if filename.ends_with(".zip") {
85            filename.trim_end_matches(".zip")
86        } else {
87            filename
88        };
89
90        name.to_string()
91    }
92
93    fn extract_host_from_url(&self, url: &str) -> String {
94        if let Some(start) = url.find("://") {
95            let after_protocol = &url[start + 3..];
96            if let Some(end) = after_protocol.find('/') {
97                return after_protocol[..end].to_string();
98            }
99            return after_protocol.to_string();
100        }
101        "unknown".to_string()
102    }
103}
104
105impl Default for ArchiveProvider {
106    fn default() -> Self {
107        Self::new()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_can_handle() {
117        let provider = ArchiveProvider::new();
118        assert!(provider.can_handle("https://example.com/project.tar.gz"));
119        assert!(provider.can_handle("https://example.com/project.tgz"));
120        assert!(provider.can_handle("https://example.com/project.tar.bz2"));
121        assert!(provider.can_handle("https://example.com/project.tar.xz"));
122        assert!(provider.can_handle("https://example.com/project.zip"));
123        assert!(provider.can_handle("https://example.com/archive/main.tar.gz"));
124        assert!(provider.can_handle("https://example.com/tarball/main"));
125        assert!(provider.can_handle("https://example.com/zipball/main"));
126        assert!(!provider.can_handle("https://github.com/user/repo"));
127    }
128
129    #[test]
130    fn test_parse_tar_gz_url() {
131        let provider = ArchiveProvider::new();
132
133        let parsed = provider
134            .parse_url("https://example.com/myproject.tar.gz")
135            .unwrap();
136        assert_eq!(parsed.owner, "archive");
137        assert_eq!(parsed.repo, "myproject");
138        assert_eq!(parsed.project_name, "myproject@main");
139        assert_eq!(parsed.branch_or_commit, None);
140        assert!(!parsed.is_commit);
141        assert_eq!(parsed.host.as_ref().unwrap(), "example.com");
142    }
143
144    #[test]
145    fn test_parse_tgz_url() {
146        let provider = ArchiveProvider::new();
147
148        let parsed = provider
149            .parse_url("https://cdn.example.com/releases/v1.0.0.tgz")
150            .unwrap();
151        assert_eq!(parsed.owner, "archive");
152        assert_eq!(parsed.repo, "v1.0.0");
153        assert_eq!(parsed.project_name, "v1.0.0@main");
154        assert_eq!(parsed.host.as_ref().unwrap(), "cdn.example.com");
155    }
156
157    #[test]
158    fn test_parse_zip_url() {
159        let provider = ArchiveProvider::new();
160
161        let parsed = provider
162            .parse_url("https://releases.example.com/project-v2.0.zip")
163            .unwrap();
164        assert_eq!(parsed.owner, "archive");
165        assert_eq!(parsed.repo, "project-v2.0");
166        assert_eq!(parsed.project_name, "project-v2.0@main");
167        assert_eq!(parsed.host.as_ref().unwrap(), "releases.example.com");
168    }
169
170    #[test]
171    fn test_extract_name_from_filename() {
172        let provider = ArchiveProvider::new();
173
174        assert_eq!(
175            provider.extract_name_from_filename("project.tar.gz"),
176            "project"
177        );
178        assert_eq!(
179            provider.extract_name_from_filename("mylib-v1.0.0.tgz"),
180            "mylib-v1.0.0"
181        );
182        assert_eq!(
183            provider.extract_name_from_filename("source.tar.bz2"),
184            "source"
185        );
186        assert_eq!(
187            provider.extract_name_from_filename("archive.tar.xz"),
188            "archive"
189        );
190        assert_eq!(
191            provider.extract_name_from_filename("release.zip"),
192            "release"
193        );
194    }
195
196    #[test]
197    fn test_extract_host_from_url() {
198        let provider = ArchiveProvider::new();
199
200        assert_eq!(
201            provider.extract_host_from_url("https://example.com/file.tar.gz"),
202            "example.com"
203        );
204        assert_eq!(
205            provider.extract_host_from_url("http://cdn.example.org/releases/v1.0.tgz"),
206            "cdn.example.org"
207        );
208        assert_eq!(
209            provider.extract_host_from_url("https://api.github.com/repos/user/repo/tarball/main"),
210            "api.github.com"
211        );
212    }
213
214    #[test]
215    fn test_get_project_name() {
216        let provider = ArchiveProvider::new();
217
218        assert_eq!(
219            provider.get_project_name("https://example.com/myproject.tar.gz"),
220            "myproject"
221        );
222        assert_eq!(
223            provider.get_project_name("https://releases.example.com/v1.2.3.tgz"),
224            "v1.2.3"
225        );
226    }
227}