1use debversion::Version;
4use std::cmp::Ordering;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Release {
9 pub version: String,
11 pub url: String,
13 pub pgpsigurl: Option<String>,
15 pub target_filename: Option<String>,
17 pub package_version: Option<String>,
19}
20
21impl Release {
22 pub fn new(
34 version: impl Into<String>,
35 url: impl Into<String>,
36 pgpsigurl: Option<String>,
37 ) -> Self {
38 Self {
39 version: version.into(),
40 url: url.into(),
41 pgpsigurl,
42 target_filename: None,
43 package_version: None,
44 }
45 }
46
47 pub fn new_full(
65 version: impl Into<String>,
66 url: impl Into<String>,
67 pgpsigurl: Option<String>,
68 target_filename: Option<String>,
69 package_version: Option<String>,
70 ) -> Self {
71 Self {
72 version: version.into(),
73 url: url.into(),
74 pgpsigurl,
75 target_filename,
76 package_version,
77 }
78 }
79
80 #[cfg(feature = "discover")]
98 pub async fn download(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
99 let client = reqwest::Client::new();
100 let response = client.get(&self.url).send().await?;
101 let bytes = response.bytes().await?;
102 Ok(bytes.to_vec())
103 }
104
105 #[cfg(all(feature = "discover", feature = "blocking"))]
120 pub fn download_blocking(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
121 let client = reqwest::blocking::Client::new();
122 let response = client.get(&self.url).send()?;
123 let bytes = response.bytes()?;
124 Ok(bytes.to_vec())
125 }
126}
127
128impl PartialOrd for Release {
129 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
130 Some(self.cmp(other))
131 }
132}
133
134impl Ord for Release {
135 fn cmp(&self, other: &Self) -> Ordering {
136 match (
138 self.version.parse::<Version>(),
139 other.version.parse::<Version>(),
140 ) {
141 (Ok(v1), Ok(v2)) => v1.cmp(&v2),
142 _ => self.version.cmp(&other.version),
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_release_new() {
154 let release = Release::new("1.0.0", "https://example.com/foo.tar.gz", None);
155 assert_eq!(release.version, "1.0.0");
156 assert_eq!(release.url, "https://example.com/foo.tar.gz");
157 assert_eq!(release.pgpsigurl, None);
158
159 let release = Release::new(
160 "2.0.0",
161 "https://example.com/foo-2.0.0.tar.gz",
162 Some("https://example.com/foo-2.0.0.tar.gz.asc".to_string()),
163 );
164 assert_eq!(release.version, "2.0.0");
165 assert_eq!(
166 release.pgpsigurl,
167 Some("https://example.com/foo-2.0.0.tar.gz.asc".to_string())
168 );
169 }
170
171 #[test]
172 fn test_release_ordering() {
173 let r1 = Release::new("1.0.0", "https://example.com/foo-1.0.0.tar.gz", None);
174 let r2 = Release::new("2.0.0", "https://example.com/foo-2.0.0.tar.gz", None);
175 let r3 = Release::new("1.5.0", "https://example.com/foo-1.5.0.tar.gz", None);
176
177 assert!(r1 < r2);
178 assert!(r2 > r1);
179 assert!(r1 < r3);
180 assert!(r3 < r2);
181 }
182
183 #[test]
184 fn test_release_ordering_debian_versions() {
185 let r1 = Release::new("1.0", "https://example.com/foo-1.0.tar.gz", None);
187 let r2 = Release::new("1.0+dfsg", "https://example.com/foo-1.0+dfsg.tar.gz", None);
188 let r3 = Release::new("1.0~rc1", "https://example.com/foo-1.0~rc1.tar.gz", None);
189
190 assert!(r3 < r1);
192 assert!(r1 < r2);
193 }
194
195 #[test]
196 fn test_release_max() {
197 let releases = vec![
198 Release::new("1.0.0", "https://example.com/foo-1.0.0.tar.gz", None),
199 Release::new("2.0.0", "https://example.com/foo-2.0.0.tar.gz", None),
200 Release::new("1.5.0", "https://example.com/foo-1.5.0.tar.gz", None),
201 ];
202
203 let max = releases.iter().max().unwrap();
204 assert_eq!(max.version, "2.0.0");
205 }
206}