bytes_radar/net/providers/
archive.rs1use 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}