1use crate::fields::{
3 Md5Checksum, MultiArch, Priority, Sha1Checksum, Sha256Checksum, Sha512Checksum,
4};
5use crate::lossless::relations::Relations;
6
7pub struct Source(deb822_lossless::Paragraph);
9
10#[cfg(feature = "python-debian")]
11impl pyo3::ToPyObject for Source {
12 fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject {
13 use pyo3::prelude::*;
14 let d = self.0.to_object(py);
15
16 let m = py.import_bound("debian.deb822").unwrap();
17 let cls = m.getattr("Sources").unwrap();
18
19 cls.call1((d,)).unwrap().to_object(py)
20 }
21}
22
23#[cfg(feature = "python-debian")]
24impl pyo3::FromPyObject<'_> for Source {
25 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
26 use pyo3::prelude::*;
27 Ok(Source(ob.extract()?))
28 }
29}
30
31impl From<deb822_lossless::Paragraph> for Source {
32 fn from(paragraph: deb822_lossless::Paragraph) -> Self {
33 Self(paragraph)
34 }
35}
36
37impl Default for Source {
38 fn default() -> Self {
39 Self(deb822_lossless::Paragraph::new())
40 }
41}
42
43impl Source {
44 pub fn new() -> Self {
46 Self(deb822_lossless::Paragraph::new())
47 }
48
49 pub fn package(&self) -> Option<String> {
51 self.0.get("Package").map(|s| s.to_string())
52 }
53
54 pub fn set_package(&mut self, package: &str) {
56 self.0.set("Package", package);
57 }
58
59 pub fn version(&self) -> Option<debversion::Version> {
61 self.0.get("Version").map(|s| s.parse().unwrap())
62 }
63
64 pub fn set_version(&mut self, version: debversion::Version) {
66 self.0.set("Version", &version.to_string());
67 }
68
69 pub fn maintainer(&self) -> Option<String> {
71 self.0.get("Maintainer").map(|s| s.to_string())
72 }
73
74 pub fn set_maintainer(&mut self, maintainer: &str) {
76 self.0.set("Maintainer", maintainer);
77 }
78
79 pub fn uploaders(&self) -> Option<Vec<String>> {
81 self.0.get("Uploaders").map(|s| {
82 s.split(',')
83 .map(|s| s.trim().to_string())
84 .collect::<Vec<String>>()
85 })
86 }
87
88 pub fn set_uploaders(&mut self, uploaders: Vec<String>) {
90 self.0.set("Uploaders", &uploaders.join(", "));
91 }
92
93 pub fn standards_version(&self) -> Option<String> {
95 self.0.get("Standards-Version").map(|s| s.to_string())
96 }
97
98 pub fn set_standards_version(&mut self, version: &str) {
100 self.0.set("Standards-Version", version);
101 }
102
103 pub fn format(&self) -> Option<String> {
105 self.0.get("Format").map(|s| s.to_string())
106 }
107
108 pub fn set_format(&mut self, format: &str) {
110 self.0.set("Format", format);
111 }
112
113 pub fn vcs_browser(&self) -> Option<String> {
115 self.0.get("Vcs-Browser").map(|s| s.to_string())
116 }
117
118 pub fn set_vcs_browser(&mut self, url: &str) {
120 self.0.set("Vcs-Browser", url);
121 }
122
123 pub fn vcs_git(&self) -> Option<String> {
125 self.0.get("Vcs-Git").map(|s| s.to_string())
126 }
127
128 pub fn set_vcs_git(&mut self, url: &str) {
130 self.0.set("Vcs-Git", url);
131 }
132
133 pub fn vcs_svn(&self) -> Option<String> {
135 self.0.get("Vcs-Svn").map(|s| s.to_string())
136 }
137
138 pub fn set_vcs_svn(&mut self, url: &str) {
140 self.0.set("Vcs-Svn", url);
141 }
142
143 pub fn vcs_hg(&self) -> Option<String> {
145 self.0.get("Vcs-Hg").map(|s| s.to_string())
146 }
147
148 pub fn set_vcs_hg(&mut self, url: &str) {
150 self.0.set("Vcs-Hg", url);
151 }
152
153 pub fn vcs_bzr(&self) -> Option<String> {
155 self.0.get("Vcs-Bzr").map(|s| s.to_string())
156 }
157
158 pub fn set_vcs_bzr(&mut self, url: &str) {
160 self.0.set("Vcs-Bzr", url);
161 }
162
163 pub fn vcs_arch(&self) -> Option<String> {
165 self.0.get("Vcs-Arch").map(|s| s.to_string())
166 }
167
168 pub fn set_vcs_arch(&mut self, url: &str) {
170 self.0.set("Vcs-Arch", url);
171 }
172
173 pub fn vcs_svk(&self) -> Option<String> {
175 self.0.get("Vcs-Svk").map(|s| s.to_string())
176 }
177
178 pub fn set_vcs_svk(&mut self, url: &str) {
180 self.0.set("Vcs-Svk", url);
181 }
182
183 pub fn vcs_darcs(&self) -> Option<String> {
185 self.0.get("Vcs-Darcs").map(|s| s.to_string())
186 }
187
188 pub fn set_vcs_darcs(&mut self, url: &str) {
190 self.0.set("Vcs-Darcs", url);
191 }
192
193 pub fn vcs_mtn(&self) -> Option<String> {
195 self.0.get("Vcs-Mtn").map(|s| s.to_string())
196 }
197
198 pub fn set_vcs_mtn(&mut self, url: &str) {
200 self.0.set("Vcs-Mtn", url);
201 }
202
203 pub fn vcs_cvs(&self) -> Option<String> {
205 self.0.get("Vcs-Cvs").map(|s| s.to_string())
206 }
207
208 pub fn set_vcs_cvs(&mut self, url: &str) {
210 self.0.set("Vcs-Cvs", url);
211 }
212
213 pub fn build_depends(&self) -> Option<Relations> {
215 self.0.get("Build-Depends").map(|s| s.parse().unwrap())
216 }
217
218 pub fn set_build_depends(&mut self, relations: Relations) {
220 self.0.set("Build-Depends", relations.to_string().as_str());
221 }
222
223 pub fn build_depends_indep(&self) -> Option<Relations> {
225 self.0
226 .get("Build-Depends-Indep")
227 .map(|s| s.parse().unwrap())
228 }
229
230 pub fn set_build_depends_indep(&mut self, relations: Relations) {
232 self.0.set("Build-Depends-Indep", &relations.to_string());
233 }
234
235 pub fn build_depends_arch(&self) -> Option<Relations> {
237 self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap())
238 }
239
240 pub fn set_build_depends_arch(&mut self, relations: Relations) {
242 self.0.set("Build-Depends-Arch", &relations.to_string());
243 }
244
245 pub fn build_conflicts(&self) -> Option<Relations> {
247 self.0.get("Build-Conflicts").map(|s| s.parse().unwrap())
248 }
249
250 pub fn set_build_conflicts(&mut self, relations: Relations) {
252 self.0.set("Build-Conflicts", &relations.to_string());
253 }
254
255 pub fn build_conflicts_indep(&self) -> Option<Relations> {
257 self.0
258 .get("Build-Conflicts-Indep")
259 .map(|s| s.parse().unwrap())
260 }
261
262 pub fn set_build_conflicts_indep(&mut self, relations: Relations) {
264 self.0.set("Build-Conflicts-Indep", &relations.to_string());
265 }
266
267 pub fn build_conflicts_arch(&self) -> Option<Relations> {
269 self.0
270 .get("Build-Conflicts-Arch")
271 .map(|s| s.parse().unwrap())
272 }
273
274 pub fn set_build_conflicts_arch(&mut self, relations: Relations) {
276 self.0.set("Build-Conflicts-Arch", &relations.to_string());
277 }
278
279 pub fn binary(&self) -> Option<Relations> {
281 self.0.get("Binary").map(|s| s.parse().unwrap())
282 }
283
284 pub fn set_binary(&mut self, relations: Relations) {
286 self.0.set("Binary", &relations.to_string());
287 }
288
289 pub fn homepage(&self) -> Option<String> {
291 self.0.get("Homepage").map(|s| s.to_string())
292 }
293
294 pub fn set_homepage(&mut self, url: &str) {
296 self.0.set("Homepage", url);
297 }
298
299 pub fn section(&self) -> Option<String> {
301 self.0.get("Section").map(|s| s.to_string())
302 }
303
304 pub fn set_section(&mut self, section: &str) {
306 self.0.set("Section", section);
307 }
308
309 pub fn priority(&self) -> Option<Priority> {
311 self.0.get("Priority").and_then(|v| v.parse().ok())
312 }
313
314 pub fn set_priority(&mut self, priority: Priority) {
316 self.0.set("Priority", priority.to_string().as_str());
317 }
318
319 pub fn architecture(&self) -> Option<String> {
321 self.0.get("Architecture")
322 }
323
324 pub fn set_architecture(&mut self, arch: &str) {
326 self.0.set("Architecture", arch);
327 }
328
329 pub fn directory(&self) -> Option<String> {
331 self.0.get("Directory").map(|s| s.to_string())
332 }
333
334 pub fn set_directory(&mut self, dir: &str) {
336 self.0.set("Directory", dir);
337 }
338
339 pub fn testsuite(&self) -> Option<String> {
341 self.0.get("Testsuite").map(|s| s.to_string())
342 }
343
344 pub fn set_testsuite(&mut self, testsuite: &str) {
346 self.0.set("Testsuite", testsuite);
347 }
348
349 pub fn files(&self) -> Vec<Md5Checksum> {
351 self.0
352 .get("Files")
353 .map(|s| {
354 s.lines()
355 .map(|line| line.parse().unwrap())
356 .collect::<Vec<Md5Checksum>>()
357 })
358 .unwrap_or_default()
359 }
360
361 pub fn set_files(&mut self, files: Vec<Md5Checksum>) {
363 self.0.set(
364 "Files",
365 &files
366 .iter()
367 .map(|f| f.to_string())
368 .collect::<Vec<String>>()
369 .join("\n"),
370 );
371 }
372
373 pub fn checksums_sha1(&self) -> Vec<Sha1Checksum> {
375 self.0
376 .get("Checksums-Sha1")
377 .map(|s| {
378 s.lines()
379 .map(|line| line.parse().unwrap())
380 .collect::<Vec<Sha1Checksum>>()
381 })
382 .unwrap_or_default()
383 }
384
385 pub fn set_checksums_sha1(&mut self, checksums: Vec<Sha1Checksum>) {
387 self.0.set(
388 "Checksums-Sha1",
389 &checksums
390 .iter()
391 .map(|c| c.to_string())
392 .collect::<Vec<String>>()
393 .join("\n"),
394 );
395 }
396
397 pub fn checksums_sha256(&self) -> Vec<Sha256Checksum> {
399 self.0
400 .get("Checksums-Sha256")
401 .map(|s| {
402 s.lines()
403 .map(|line| line.parse().unwrap())
404 .collect::<Vec<Sha256Checksum>>()
405 })
406 .unwrap_or_default()
407 }
408
409 pub fn set_checksums_sha256(&mut self, checksums: Vec<Sha256Checksum>) {
411 self.0.set(
412 "Checksums-Sha256",
413 &checksums
414 .iter()
415 .map(|c| c.to_string())
416 .collect::<Vec<String>>()
417 .join("\n"),
418 );
419 }
420
421 pub fn checksums_sha512(&self) -> Vec<Sha512Checksum> {
423 self.0
424 .get("Checksums-Sha512")
425 .map(|s| {
426 s.lines()
427 .map(|line| line.parse().unwrap())
428 .collect::<Vec<Sha512Checksum>>()
429 })
430 .unwrap_or_default()
431 }
432
433 pub fn set_checksums_sha512(&mut self, checksums: Vec<Sha512Checksum>) {
435 self.0.set(
436 "Checksums-Sha512",
437 &checksums
438 .iter()
439 .map(|c| c.to_string())
440 .collect::<Vec<String>>()
441 .join("\n"),
442 );
443 }
444}
445
446impl std::str::FromStr for Source {
447 type Err = deb822_lossless::ParseError;
448
449 fn from_str(s: &str) -> Result<Self, Self::Err> {
450 Ok(Self(s.parse()?))
451 }
452}
453
454pub struct Package(deb822_lossless::Paragraph);
456
457#[cfg(feature = "python-debian")]
458impl pyo3::ToPyObject for Package {
459 fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject {
460 use pyo3::prelude::*;
461 let d = self.0.to_object(py);
462
463 let m = py.import_bound("debian.deb822").unwrap();
464 let cls = m.getattr("Packages").unwrap();
465
466 cls.call1((d,)).unwrap().to_object(py)
467 }
468}
469
470#[cfg(feature = "python-debian")]
471impl pyo3::FromPyObject<'_> for Package {
472 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
473 use pyo3::prelude::*;
474 Ok(Package(ob.extract()?))
475 }
476}
477
478impl Package {
479 pub fn new(paragraph: deb822_lossless::Paragraph) -> Self {
481 Self(paragraph)
482 }
483
484 pub fn name(&self) -> Option<String> {
486 self.0.get("Package").map(|s| s.to_string())
487 }
488
489 pub fn set_name(&mut self, name: &str) {
491 self.0.set("Package", name);
492 }
493
494 pub fn version(&self) -> Option<debversion::Version> {
496 self.0.get("Version").map(|s| s.parse().unwrap())
497 }
498
499 pub fn set_version(&mut self, version: debversion::Version) {
501 self.0.set("Version", &version.to_string());
502 }
503
504 pub fn installed_size(&self) -> Option<usize> {
506 self.0.get("Installed-Size").map(|s| s.parse().unwrap())
507 }
508
509 pub fn set_installed_size(&mut self, size: usize) {
511 self.0.set("Installed-Size", &size.to_string());
512 }
513
514 pub fn maintainer(&self) -> Option<String> {
516 self.0.get("Maintainer").map(|s| s.to_string())
517 }
518
519 pub fn set_maintainer(&mut self, maintainer: &str) {
521 self.0.set("Maintainer", maintainer);
522 }
523
524 pub fn architecture(&self) -> Option<String> {
526 self.0.get("Architecture").map(|s| s.to_string())
527 }
528
529 pub fn set_architecture(&mut self, arch: &str) {
531 self.0.set("Architecture", arch);
532 }
533
534 pub fn depends(&self) -> Option<Relations> {
536 self.0.get("Depends").map(|s| s.parse().unwrap())
537 }
538
539 pub fn set_depends(&mut self, relations: Relations) {
541 self.0.set("Depends", &relations.to_string());
542 }
543
544 pub fn recommends(&self) -> Option<Relations> {
546 self.0.get("Recommends").map(|s| s.parse().unwrap())
547 }
548
549 pub fn set_recommends(&mut self, relations: Relations) {
551 self.0.set("Recommends", &relations.to_string());
552 }
553
554 pub fn suggests(&self) -> Option<Relations> {
556 self.0.get("Suggests").map(|s| s.parse().unwrap())
557 }
558
559 pub fn set_suggests(&mut self, relations: Relations) {
561 self.0.set("Suggests", &relations.to_string());
562 }
563
564 pub fn enhances(&self) -> Option<Relations> {
566 self.0.get("Enhances").map(|s| s.parse().unwrap())
567 }
568
569 pub fn set_enhances(&mut self, relations: Relations) {
571 self.0.set("Enhances", &relations.to_string());
572 }
573
574 pub fn pre_depends(&self) -> Option<Relations> {
576 self.0.get("Pre-Depends").map(|s| s.parse().unwrap())
577 }
578
579 pub fn set_pre_depends(&mut self, relations: Relations) {
581 self.0.set("Pre-Depends", &relations.to_string());
582 }
583
584 pub fn breaks(&self) -> Option<Relations> {
586 self.0.get("Breaks").map(|s| s.parse().unwrap())
587 }
588
589 pub fn set_breaks(&mut self, relations: Relations) {
591 self.0.set("Breaks", &relations.to_string());
592 }
593
594 pub fn conflicts(&self) -> Option<Relations> {
596 self.0.get("Conflicts").map(|s| s.parse().unwrap())
597 }
598
599 pub fn set_conflicts(&mut self, relations: Relations) {
601 self.0.set("Conflicts", &relations.to_string());
602 }
603
604 pub fn replaces(&self) -> Option<Relations> {
606 self.0.get("Replaces").map(|s| s.parse().unwrap())
607 }
608
609 pub fn set_replaces(&mut self, relations: Relations) {
611 self.0.set("Replaces", &relations.to_string());
612 }
613
614 pub fn provides(&self) -> Option<Relations> {
616 self.0.get("Provides").map(|s| s.parse().unwrap())
617 }
618
619 pub fn set_provides(&mut self, relations: Relations) {
621 self.0.set("Provides", &relations.to_string());
622 }
623
624 pub fn section(&self) -> Option<String> {
626 self.0.get("Section").map(|s| s.to_string())
627 }
628
629 pub fn set_section(&mut self, section: &str) {
631 self.0.set("Section", section);
632 }
633
634 pub fn priority(&self) -> Option<Priority> {
636 self.0.get("Priority").and_then(|v| v.parse().ok())
637 }
638
639 pub fn set_priority(&mut self, priority: Priority) {
641 self.0.set("Priority", priority.to_string().as_str());
642 }
643
644 pub fn description(&self) -> Option<String> {
646 self.0.get("Description").map(|s| s.to_string())
647 }
648
649 pub fn set_description(&mut self, description: &str) {
651 self.0.set("Description", description);
652 }
653
654 pub fn homepage(&self) -> Option<url::Url> {
656 self.0.get("Homepage").map(|s| s.parse().unwrap())
657 }
658
659 pub fn set_homepage(&mut self, url: &url::Url) {
661 self.0.set("Homepage", url.as_ref());
662 }
663
664 pub fn source(&self) -> Option<String> {
666 self.0.get("Source").map(|s| s.to_string())
667 }
668
669 pub fn set_source(&mut self, source: &str) {
671 self.0.set("Source", source);
672 }
673
674 pub fn description_md5(&self) -> Option<String> {
676 self.0.get("Description-md5").map(|s| s.to_string())
677 }
678
679 pub fn set_description_md5(&mut self, md5: &str) {
681 self.0.set("Description-md5", md5);
682 }
683
684 pub fn tags(&self, tag: &str) -> Option<Vec<String>> {
686 self.0
687 .get(tag)
688 .map(|s| s.split(',').map(|s| s.trim().to_string()).collect())
689 }
690
691 pub fn set_tags(&mut self, tag: &str, tags: Vec<String>) {
693 self.0.set(tag, &tags.join(", "));
694 }
695
696 pub fn filename(&self) -> Option<String> {
698 self.0.get("Filename").map(|s| s.to_string())
699 }
700
701 pub fn set_filename(&mut self, filename: &str) {
703 self.0.set("Filename", filename);
704 }
705
706 pub fn size(&self) -> Option<usize> {
708 self.0.get("Size").map(|s| s.parse().unwrap())
709 }
710
711 pub fn set_size(&mut self, size: usize) {
713 self.0.set("Size", &size.to_string());
714 }
715
716 pub fn md5sum(&self) -> Option<String> {
718 self.0.get("MD5sum").map(|s| s.to_string())
719 }
720
721 pub fn set_md5sum(&mut self, md5sum: &str) {
723 self.0.set("MD5sum", md5sum);
724 }
725
726 pub fn sha256(&self) -> Option<String> {
728 self.0.get("SHA256").map(|s| s.to_string())
729 }
730
731 pub fn set_sha256(&mut self, sha256: &str) {
733 self.0.set("SHA256", sha256);
734 }
735
736 pub fn multi_arch(&self) -> Option<MultiArch> {
738 self.0.get("Multi-Arch").map(|s| s.parse().unwrap())
739 }
740
741 pub fn set_multi_arch(&mut self, arch: MultiArch) {
743 self.0.set("Multi-Arch", arch.to_string().as_str());
744 }
745}
746
747impl std::str::FromStr for Package {
748 type Err = deb822_lossless::ParseError;
749
750 fn from_str(s: &str) -> Result<Self, Self::Err> {
751 Ok(Self(s.parse()?))
752 }
753}
754
755pub struct Release(deb822_lossless::Paragraph);
757
758#[cfg(feature = "python-debian")]
759impl pyo3::ToPyObject for Release {
760 fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject {
761 use pyo3::prelude::*;
762 let d = self.0.to_object(py);
763
764 let m = py.import_bound("debian.deb822").unwrap();
765 let cls = m.getattr("Release").unwrap();
766
767 cls.call1((d,)).unwrap().to_object(py)
768 }
769}
770
771#[cfg(feature = "python-debian")]
772impl pyo3::FromPyObject<'_> for Release {
773 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
774 use pyo3::prelude::*;
775 Ok(Release(ob.extract()?))
776 }
777}
778
779impl Release {
780 pub fn new(paragraph: deb822_lossless::Paragraph) -> Self {
782 Self(paragraph)
783 }
784
785 pub fn origin(&self) -> Option<String> {
787 self.0.get("Origin").map(|s| s.to_string())
788 }
789
790 pub fn set_origin(&mut self, origin: &str) {
792 self.0.set("Origin", origin);
793 }
794
795 pub fn label(&self) -> Option<String> {
797 self.0.get("Label").map(|s| s.to_string())
798 }
799
800 pub fn set_label(&mut self, label: &str) {
802 self.0.set("Label", label);
803 }
804
805 pub fn suite(&self) -> Option<String> {
807 self.0.get("Suite").map(|s| s.to_string())
808 }
809
810 pub fn set_suite(&mut self, suite: &str) {
812 self.0.set("Suite", suite);
813 }
814
815 pub fn codename(&self) -> Option<String> {
817 self.0.get("Codename").map(|s| s.to_string())
818 }
819
820 pub fn set_codename(&mut self, codename: &str) {
822 self.0.set("Codename", codename);
823 }
824
825 pub fn changelogs(&self) -> Option<Vec<String>> {
827 self.0.get("Changelogs").map(|s| {
828 s.split(',')
829 .map(|s| s.trim().to_string())
830 .collect::<Vec<String>>()
831 })
832 }
833
834 pub fn set_changelogs(&mut self, changelogs: Vec<String>) {
836 self.0.set("Changelogs", &changelogs.join(", "));
837 }
838
839 #[cfg(feature = "chrono")]
840 pub fn date(&self) -> Option<chrono::DateTime<chrono::FixedOffset>> {
842 self.0
843 .get("Date")
844 .as_ref()
845 .map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap())
846 }
847
848 #[cfg(feature = "chrono")]
849 pub fn set_date(&mut self, date: chrono::DateTime<chrono::FixedOffset>) {
851 self.0.set("Date", date.to_rfc2822().as_str());
852 }
853
854 #[cfg(feature = "chrono")]
855 pub fn valid_until(&self) -> Option<chrono::DateTime<chrono::FixedOffset>> {
857 self.0
858 .get("Valid-Until")
859 .as_ref()
860 .map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap())
861 }
862
863 #[cfg(feature = "chrono")]
864 pub fn set_valid_until(&mut self, date: chrono::DateTime<chrono::FixedOffset>) {
866 self.0.set("Valid-Until", date.to_rfc2822().as_str());
867 }
868
869 pub fn acquire_by_hash(&self) -> bool {
871 self.0
872 .get("Acquire-By-Hash")
873 .map(|s| s == "yes")
874 .unwrap_or(false)
875 }
876
877 pub fn set_acquire_by_hash(&mut self, acquire_by_hash: bool) {
879 self.0.set(
880 "Acquire-By-Hash",
881 if acquire_by_hash { "yes" } else { "no" },
882 );
883 }
884
885 pub fn no_support_for_architecture_all(&self) -> bool {
887 self.0
888 .get("No-Support-For-Architecture-All")
889 .map(|s| s == "yes")
890 .unwrap_or(false)
891 }
892
893 pub fn set_no_support_for_architecture_all(&mut self, no_support_for_architecture_all: bool) {
895 self.0.set(
896 "No-Support-For-Architecture-All",
897 if no_support_for_architecture_all {
898 "yes"
899 } else {
900 "no"
901 },
902 );
903 }
904
905 pub fn architectures(&self) -> Option<Vec<String>> {
907 self.0.get("Architectures").map(|s| {
908 s.split_whitespace()
909 .map(|s| s.trim().to_string())
910 .collect::<Vec<String>>()
911 })
912 }
913
914 pub fn set_architectures(&mut self, architectures: Vec<String>) {
916 self.0.set("Architectures", &architectures.join(" "));
917 }
918
919 pub fn components(&self) -> Option<Vec<String>> {
921 self.0.get("Components").map(|s| {
922 s.split_whitespace()
923 .map(|s| s.trim().to_string())
924 .collect::<Vec<String>>()
925 })
926 }
927
928 pub fn set_components(&mut self, components: Vec<String>) {
930 self.0.set("Components", &components.join(" "));
931 }
932
933 pub fn description(&self) -> Option<String> {
935 self.0.get("Description").map(|s| s.to_string())
936 }
937
938 pub fn set_description(&mut self, description: &str) {
940 self.0.set("Description", description);
941 }
942
943 pub fn checksums_md5(&self) -> Vec<Md5Checksum> {
945 self.0
946 .get("MD5Sum")
947 .map(|s| {
948 s.lines()
949 .map(|line| line.parse().unwrap())
950 .collect::<Vec<Md5Checksum>>()
951 })
952 .unwrap_or_default()
953 }
954
955 pub fn set_checksums_md5(&mut self, files: Vec<Md5Checksum>) {
957 self.0.set(
958 "MD5Sum",
959 &files
960 .iter()
961 .map(|f| f.to_string())
962 .collect::<Vec<String>>()
963 .join("\n"),
964 );
965 }
966
967 pub fn checksums_sha1(&self) -> Vec<Sha1Checksum> {
969 self.0
970 .get("SHA1")
971 .map(|s| {
972 s.lines()
973 .map(|line| line.parse().unwrap())
974 .collect::<Vec<Sha1Checksum>>()
975 })
976 .unwrap_or_default()
977 }
978
979 pub fn set_checksums_sha1(&mut self, checksums: Vec<Sha1Checksum>) {
981 self.0.set(
982 "SHA1",
983 &checksums
984 .iter()
985 .map(|c| c.to_string())
986 .collect::<Vec<String>>()
987 .join("\n"),
988 );
989 }
990
991 pub fn checksums_sha256(&self) -> Vec<Sha256Checksum> {
993 self.0
994 .get("SHA256")
995 .map(|s| {
996 s.lines()
997 .map(|line| line.parse().unwrap())
998 .collect::<Vec<Sha256Checksum>>()
999 })
1000 .unwrap_or_default()
1001 }
1002
1003 pub fn set_checksums_sha256(&mut self, checksums: Vec<Sha256Checksum>) {
1005 self.0.set(
1006 "SHA256",
1007 &checksums
1008 .iter()
1009 .map(|c| c.to_string())
1010 .collect::<Vec<String>>()
1011 .join("\n"),
1012 );
1013 }
1014
1015 pub fn checksums_sha512(&self) -> Vec<Sha512Checksum> {
1017 self.0
1018 .get("SHA512")
1019 .map(|s| {
1020 s.lines()
1021 .map(|line| line.parse().unwrap())
1022 .collect::<Vec<Sha512Checksum>>()
1023 })
1024 .unwrap_or_default()
1025 }
1026
1027 pub fn set_checksums_sha512(&mut self, checksums: Vec<Sha512Checksum>) {
1029 self.0.set(
1030 "SHA512",
1031 &checksums
1032 .iter()
1033 .map(|c| c.to_string())
1034 .collect::<Vec<String>>()
1035 .join("\n"),
1036 );
1037 }
1038}
1039
1040impl std::str::FromStr for Release {
1041 type Err = deb822_lossless::ParseError;
1042
1043 fn from_str(s: &str) -> Result<Self, Self::Err> {
1044 Ok(Self(s.parse()?))
1045 }
1046}
1047
1048#[cfg(test)]
1049mod tests {
1050 use super::*;
1051 use crate::fields::PackageListEntry;
1052
1053 #[test]
1054 fn test_parse_package_list() {
1055 let s = "package1 binary section standard extra1=foo extra2=bar";
1056 let p: PackageListEntry = s.parse().unwrap();
1057 assert_eq!(p.package, "package1");
1058 assert_eq!(p.package_type, "binary");
1059 assert_eq!(p.section, "section");
1060 assert_eq!(p.priority, super::Priority::Standard);
1061 assert_eq!(p.extra.get("extra1"), Some(&"foo".to_string()));
1062 assert_eq!(p.extra.get("extra2"), Some(&"bar".to_string()));
1063 }
1064
1065 #[test]
1066 fn test_parse_package_list_no_extra() {
1067 let s = "package1 binary section standard";
1068 let p: PackageListEntry = s.parse().unwrap();
1069 assert_eq!(p.package, "package1");
1070 assert_eq!(p.package_type, "binary");
1071 assert_eq!(p.section, "section");
1072 assert_eq!(p.priority, super::Priority::Standard);
1073 assert!(p.extra.is_empty());
1074 }
1075
1076 #[test]
1077 fn test_files() {
1078 let s = "md5sum 1234 filename";
1079 let f: super::Md5Checksum = s.parse().unwrap();
1080 assert_eq!(f.md5sum, "md5sum");
1081 assert_eq!(f.size, 1234);
1082 assert_eq!(f.filename, "filename");
1083 }
1084
1085 #[test]
1086 fn test_sha1_checksum() {
1087 let s = "sha1 1234 filename";
1088 let f: super::Sha1Checksum = s.parse().unwrap();
1089 assert_eq!(f.sha1, "sha1");
1090 assert_eq!(f.size, 1234);
1091 assert_eq!(f.filename, "filename");
1092 }
1093
1094 #[test]
1095 fn test_sha256_checksum() {
1096 let s = "sha256 1234 filename";
1097 let f: super::Sha256Checksum = s.parse().unwrap();
1098 assert_eq!(f.sha256, "sha256");
1099 assert_eq!(f.size, 1234);
1100 assert_eq!(f.filename, "filename");
1101 }
1102
1103 #[test]
1104 fn test_sha512_checksum() {
1105 let s = "sha512 1234 filename";
1106 let f: super::Sha512Checksum = s.parse().unwrap();
1107 assert_eq!(f.sha512, "sha512");
1108 assert_eq!(f.size, 1234);
1109 assert_eq!(f.filename, "filename");
1110 }
1111
1112 #[test]
1113 fn test_source() {
1114 let s = r#"Package: foo
1115Version: 1.0
1116Maintainer: John Doe <john@example.com>
1117Uploaders: Jane Doe <jane@example.com>
1118Standards-Version: 3.9.8
1119Format: 3.0 (quilt)
1120Vcs-Browser: https://example.com/foo
1121Vcs-Git: https://example.com/foo.git
1122Build-Depends: debhelper (>= 9)
1123Build-Depends-Indep: python
1124Build-Depends-Arch: gcc
1125Build-Conflicts: bar
1126Build-Conflicts-Indep: python
1127Build-Conflicts-Arch: gcc
1128Binary: foo, bar
1129Homepage: https://example.com/foo
1130Section: devel
1131Priority: optional
1132Architecture: any
1133Directory: pool/main/f/foo
1134Files:
1135 25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz
1136Checksums-Sha1:
1137 b72b5fae3b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz
1138"#;
1139 let p: super::Source = s.parse().unwrap();
1140 assert_eq!(p.package(), Some("foo".to_string()));
1141 assert_eq!(p.version(), Some("1.0".parse().unwrap()));
1142 assert_eq!(
1143 p.maintainer(),
1144 Some("John Doe <john@example.com>".to_string())
1145 );
1146 assert_eq!(
1147 p.uploaders(),
1148 Some(vec!["Jane Doe <jane@example.com>".to_string()])
1149 );
1150 assert_eq!(p.standards_version(), Some("3.9.8".to_string()));
1151 assert_eq!(p.format(), Some("3.0 (quilt)".to_string()));
1152 assert_eq!(p.vcs_browser(), Some("https://example.com/foo".to_string()));
1153 assert_eq!(p.vcs_git(), Some("https://example.com/foo.git".to_string()));
1154 assert_eq!(
1155 p.build_depends_indep().map(|x| x.to_string()),
1156 Some("python".parse().unwrap())
1157 );
1158 assert_eq!(p.build_depends(), Some("debhelper (>= 9)".parse().unwrap()));
1159 assert_eq!(p.build_depends_arch(), Some("gcc".parse().unwrap()));
1160 assert_eq!(p.build_conflicts(), Some("bar".parse().unwrap()));
1161 assert_eq!(p.build_conflicts_indep(), Some("python".parse().unwrap()));
1162 assert_eq!(p.build_conflicts_arch(), Some("gcc".parse().unwrap()));
1163 assert_eq!(p.binary(), Some("foo, bar".parse().unwrap()));
1164 assert_eq!(p.homepage(), Some("https://example.com/foo".to_string()));
1165 assert_eq!(p.section(), Some("devel".to_string()));
1166 assert_eq!(p.priority(), Some(super::Priority::Optional));
1167 assert_eq!(p.architecture(), Some("any".to_string()));
1168 assert_eq!(p.directory(), Some("pool/main/f/foo".to_string()));
1169 assert_eq!(p.files().len(), 1);
1170 assert_eq!(
1171 p.files()[0].md5sum,
1172 "25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3".to_string()
1173 );
1174 assert_eq!(p.files()[0].size, 1234);
1175 assert_eq!(p.files()[0].filename, "foo_1.0.tar.gz".to_string());
1176 assert_eq!(p.checksums_sha1().len(), 1);
1177 assert_eq!(
1178 p.checksums_sha1()[0].sha1,
1179 "b72b5fae3b3b3b3b3b3b3b3b3b3b3b3".to_string()
1180 );
1181 }
1182
1183 #[test]
1184 fn test_package() {
1185 let s = r#"Package: foo
1186Version: 1.0
1187Source: bar
1188Maintainer: John Doe <john@example.com>
1189Architecture: any
1190Depends: bar
1191Recommends: baz
1192Suggests: qux
1193Enhances: quux
1194Pre-Depends: quuz
1195Breaks: corge
1196Conflicts: grault
1197Replaces: garply
1198Provides: waldo
1199Section: devel
1200Priority: optional
1201Description: Foo is a bar
1202Homepage: https://example.com/foo
1203Description-md5: 1234
1204Tags: foo, bar
1205Filename: pool/main/f/foo/foo_1.0.deb
1206Size: 1234
1207Installed-Size: 1234
1208MD5sum: 1234
1209SHA256: 1234
1210Multi-Arch: same
1211"#;
1212 let p: super::Package = s.parse().unwrap();
1213 assert_eq!(p.name(), Some("foo".to_string()));
1214 assert_eq!(p.version(), Some("1.0".parse().unwrap()));
1215 assert_eq!(p.source(), Some("bar".to_string()));
1216 assert_eq!(
1217 p.maintainer(),
1218 Some("John Doe <john@example.com>".to_string())
1219 );
1220 assert_eq!(p.architecture(), Some("any".to_string()));
1221 assert_eq!(p.depends(), Some("bar".parse().unwrap()));
1222 assert_eq!(p.recommends(), Some("baz".parse().unwrap()));
1223 assert_eq!(p.suggests(), Some("qux".parse().unwrap()));
1224 assert_eq!(p.enhances(), Some("quux".parse().unwrap()));
1225 assert_eq!(p.pre_depends(), Some("quuz".parse().unwrap()));
1226 assert_eq!(p.breaks(), Some("corge".parse().unwrap()));
1227 assert_eq!(p.conflicts(), Some("grault".parse().unwrap()));
1228 assert_eq!(p.replaces(), Some("garply".parse().unwrap()));
1229 assert_eq!(p.provides(), Some("waldo".parse().unwrap()));
1230 assert_eq!(p.section(), Some("devel".to_string()));
1231 assert_eq!(p.priority(), Some(super::Priority::Optional));
1232 assert_eq!(p.description(), Some("Foo is a bar".to_string()));
1233 assert_eq!(
1234 p.homepage(),
1235 Some(url::Url::parse("https://example.com/foo").unwrap())
1236 );
1237 assert_eq!(p.description_md5(), Some("1234".to_string()));
1238 assert_eq!(
1239 p.tags("Tags"),
1240 Some(vec!["foo".to_string(), "bar".to_string()])
1241 );
1242 assert_eq!(
1243 p.filename(),
1244 Some("pool/main/f/foo/foo_1.0.deb".to_string())
1245 );
1246 assert_eq!(p.size(), Some(1234));
1247 assert_eq!(p.installed_size(), Some(1234));
1248 assert_eq!(p.md5sum(), Some("1234".to_string()));
1249 assert_eq!(p.sha256(), Some("1234".to_string()));
1250 assert_eq!(p.multi_arch(), Some(MultiArch::Same));
1251 }
1252
1253 #[test]
1254 fn test_release() {
1255 let s = include_str!("../testdata/Release");
1256 let release: super::Release = s.parse().unwrap();
1257
1258 assert_eq!(release.origin(), Some("Debian".to_string()));
1259 assert_eq!(release.label(), Some("Debian".to_string()));
1260 assert_eq!(release.suite(), Some("testing".to_string()));
1261 assert_eq!(
1262 release.architectures(),
1263 vec![
1264 "all".to_string(),
1265 "amd64".to_string(),
1266 "arm64".to_string(),
1267 "armel".to_string(),
1268 "armhf".to_string()
1269 ]
1270 .into()
1271 );
1272 assert_eq!(
1273 release.components(),
1274 vec![
1275 "main".to_string(),
1276 "contrib".to_string(),
1277 "non-free-firmware".to_string(),
1278 "non-free".to_string()
1279 ]
1280 .into()
1281 );
1282 assert_eq!(
1283 release.description(),
1284 Some("Debian x.y Testing distribution - Not Released".to_string())
1285 );
1286 assert_eq!(318, release.checksums_md5().len());
1287 }
1288}