1use crate::lossy::Relations;
3use deb822_fast::{FromDeb822, FromDeb822Paragraph, ToDeb822, ToDeb822Paragraph};
4
5fn deserialize_components(value: &str) -> Result<Vec<String>, String> {
6 Ok(value.split_whitespace().map(|s| s.to_string()).collect())
7}
8
9fn join_whitespace(components: &[String]) -> String {
10 components.join(" ")
11}
12
13fn deserialize_architectures(value: &str) -> Result<Vec<String>, String> {
14 Ok(value.split_whitespace().map(|s| s.to_string()).collect())
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
18pub struct Release {
20 #[deb822(field = "Codename")]
21 pub codename: String,
23
24 #[deb822(
25 field = "Components",
26 deserialize_with = deserialize_components,
27 serialize_with = join_whitespace
28 )]
29 pub components: Vec<String>,
31
32 #[deb822(
33 field = "Architectures",
34 deserialize_with = deserialize_architectures,
35 serialize_with = join_whitespace
36 )]
37 pub architectures: Vec<String>,
39
40 #[deb822(field = "Description")]
41 pub description: String,
43
44 #[deb822(field = "Origin")]
45 pub origin: String,
47
48 #[deb822(field = "Label")]
49 pub label: String,
51
52 #[deb822(field = "Suite")]
53 pub suite: String,
55
56 #[deb822(field = "Version")]
57 pub version: String,
59
60 #[deb822(field = "Date")]
61 pub date: String,
63
64 #[deb822(field = "NotAutomatic")]
65 pub not_automatic: bool,
67
68 #[deb822(field = "ButAutomaticUpgrades")]
69 pub but_automatic_upgrades: bool,
71
72 #[deb822(field = "Acquire-By-Hash")]
73 pub acquire_by_hash: bool,
75}
76
77fn deserialize_binaries(value: &str) -> Result<Vec<String>, String> {
78 Ok(value.split_whitespace().map(|s| s.to_string()).collect())
79}
80
81fn join_lines(components: &[String]) -> String {
82 components.join("\n")
83}
84
85fn deserialize_package_list(value: &str) -> Result<Vec<String>, String> {
86 Ok(value.split('\n').map(|s| s.to_string()).collect())
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
90pub struct Source {
92 #[deb822(field = "Directory")]
93 pub directory: String,
95
96 #[deb822(field = "Description")]
97 pub description: Option<String>,
99
100 #[deb822(field = "Version")]
101 pub version: debversion::Version,
103
104 #[deb822(field = "Package")]
105 pub package: String,
107
108 #[deb822(field = "Binary", deserialize_with = deserialize_binaries, serialize_with = join_whitespace)]
109 pub binaries: Option<Vec<String>>,
111
112 #[deb822(field = "Maintainer")]
113 pub maintainer: Option<String>,
115
116 #[deb822(field = "Build-Depends")]
117 pub build_depends: Option<String>,
119
120 #[deb822(field = "Build-Depends-Indep")]
121 pub build_depends_indep: Option<Relations>,
123
124 #[deb822(field = "Build-Conflicts")]
125 pub build_conflicts: Option<Relations>,
127
128 #[deb822(field = "Build-Conflicts-Indep")]
129 pub build_conflicts_indep: Option<Relations>,
131
132 #[deb822(field = "Standards-Version")]
133 pub standards_version: Option<String>,
135
136 #[deb822(field = "Homepage")]
137 pub homepage: Option<String>,
139
140 #[deb822(field = "Autobuild")]
141 pub autobuild: Option<bool>,
143
144 #[deb822(field = "Testsuite")]
145 pub testsuite: Option<String>,
147
148 #[deb822(field = "Vcs-Browser")]
149 pub vcs_browser: Option<String>,
151
152 #[deb822(field = "Vcs-Git")]
153 pub vcs_git: Option<String>,
155
156 #[deb822(field = "Vcs-Bzr")]
157 pub vcs_bzr: Option<String>,
159
160 #[deb822(field = "Vcs-Hg")]
161 pub vcs_hg: Option<String>,
163
164 #[deb822(field = "Vcs-Svn")]
165 pub vcs_svn: Option<String>,
167
168 #[deb822(field = "Vcs-Darcs")]
169 pub vcs_darcs: Option<String>,
171
172 #[deb822(field = "Vcs-Cvs")]
173 pub vcs_cvs: Option<String>,
175
176 #[deb822(field = "Vcs-Arch")]
177 pub vcs_arch: Option<String>,
179
180 #[deb822(field = "Vcs-Mtn")]
181 pub vcs_mtn: Option<String>,
183
184 #[deb822(field = "Priority")]
185 pub priority: Option<crate::fields::Priority>,
187
188 #[deb822(field = "Section")]
189 pub section: Option<String>,
191
192 #[deb822(field = "Format")]
193 pub format: Option<String>,
195
196 #[deb822(field = "Package-List", deserialize_with = deserialize_package_list, serialize_with = join_lines)]
197 pub package_list: Vec<String>,
199}
200
201impl std::str::FromStr for Source {
202 type Err = String;
203
204 fn from_str(s: &str) -> Result<Self, Self::Err> {
205 let para = s
206 .parse::<deb822_fast::Paragraph>()
207 .map_err(|e| e.to_string())?;
208
209 FromDeb822Paragraph::from_paragraph(¶)
210 }
211}
212
213impl std::fmt::Display for Source {
214 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
215 let para: deb822_fast::Paragraph = self.to_paragraph();
216 write!(f, "{}", para)
217 }
218}
219
220#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
222pub struct Package {
223 #[deb822(field = "Package")]
225 pub name: String,
226
227 #[deb822(field = "Version")]
229 pub version: debversion::Version,
230
231 #[deb822(field = "Architecture")]
233 pub architecture: String,
234
235 #[deb822(field = "Maintainer")]
237 pub maintainer: Option<String>,
238
239 #[deb822(field = "Installed-Size")]
241 pub installed_size: Option<usize>,
242
243 #[deb822(field = "Depends")]
245 pub depends: Option<Relations>,
246
247 #[deb822(field = "Pre-Depends")]
249 pub pre_depends: Option<Relations>,
250
251 #[deb822(field = "Recommends")]
253 pub recommends: Option<Relations>,
254
255 #[deb822(field = "Suggests")]
257 pub suggests: Option<Relations>,
258
259 #[deb822(field = "Enhances")]
261 pub enhances: Option<Relations>,
262
263 #[deb822(field = "Breaks")]
265 pub breaks: Option<Relations>,
266
267 #[deb822(field = "Conflicts")]
269 pub conflicts: Option<Relations>,
270
271 #[deb822(field = "Provides")]
273 pub provides: Option<Relations>,
274
275 #[deb822(field = "Replaces")]
277 pub replaces: Option<Relations>,
278
279 #[deb822(field = "Built-Using")]
281 pub built_using: Option<Relations>,
282
283 #[deb822(field = "Description")]
285 pub description: Option<String>,
286
287 #[deb822(field = "Homepage")]
289 pub homepage: Option<String>,
290
291 #[deb822(field = "Priority")]
293 pub priority: Option<crate::fields::Priority>,
294
295 #[deb822(field = "Section")]
297 pub section: Option<String>,
298
299 #[deb822(field = "Essential")]
301 pub essential: Option<bool>,
302
303 #[deb822(field = "Tag")]
305 pub tag: Option<String>,
306
307 #[deb822(field = "Size")]
309 pub size: Option<usize>,
310
311 #[deb822(field = "MD5sum")]
313 pub md5sum: Option<String>,
314
315 #[deb822(field = "SHA256")]
317 pub sha256: Option<String>,
318
319 #[deb822(field = "Description-MD5")]
321 pub description_md5: Option<String>,
322}
323
324impl std::str::FromStr for Package {
325 type Err = String;
326
327 fn from_str(s: &str) -> Result<Self, Self::Err> {
328 let para = s
329 .parse::<deb822_fast::Paragraph>()
330 .map_err(|e| e.to_string())?;
331
332 FromDeb822Paragraph::from_paragraph(¶)
333 }
334}
335
336impl std::fmt::Display for Package {
337 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
338 let para: deb822_fast::Paragraph = self.to_paragraph();
339 write!(f, "{}", para)
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use deb822_fast::Paragraph;
347 use deb822_fast::ToDeb822Paragraph;
348
349 #[test]
350 fn test_release() {
351 let release = Release {
352 codename: "focal".to_string(),
353 components: vec!["main".to_string(), "restricted".to_string()],
354 architectures: vec!["amd64".to_string(), "arm64".to_string()],
355 description: "Ubuntu 20.04 LTS".to_string(),
356 origin: "Ubuntu".to_string(),
357 label: "Ubuntu".to_string(),
358 suite: "focal".to_string(),
359 version: "20.04".to_string(),
360 date: "Thu, 23 Apr 2020 17:19:19 UTC".to_string(),
361 not_automatic: false,
362 but_automatic_upgrades: true,
363 acquire_by_hash: true,
364 };
365
366 let deb822 = r#"Codename: focal
367Components: main restricted
368Architectures: amd64 arm64
369Description: Ubuntu 20.04 LTS
370Origin: Ubuntu
371Label: Ubuntu
372Suite: focal
373Version: 20.04
374Date: Thu, 23 Apr 2020 17:19:19 UTC
375NotAutomatic: false
376ButAutomaticUpgrades: true
377Acquire-By-Hash: true
378"#;
379
380 let para = deb822.parse::<Paragraph>().unwrap();
381
382 let release: deb822_fast::Paragraph = release.to_paragraph();
383
384 assert_eq!(release, para);
385 }
386
387 #[test]
388 fn test_package() {
389 let package = r#"Package: apt
390Version: 2.1.10
391Architecture: amd64
392Maintainer: APT Development Team <apt@lists.debian.org>
393Installed-Size: 3524
394Depends: libc6 (>= 2.14), libgcc1
395Pre-Depends: dpkg (>= 1.15.6)
396Recommends: gnupg
397Suggests: apt-doc, aptitude | synaptic | wajig
398"#;
399
400 let package: Package = package.parse().unwrap();
401
402 assert_eq!(package.name, "apt");
403 assert_eq!(package.version, "2.1.10".parse().unwrap());
404 assert_eq!(package.architecture, "amd64");
405 }
406}