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<'py> pyo3::IntoPyObject<'py> for Source {
12 type Target = pyo3::PyAny;
13 type Output = pyo3::Bound<'py, Self::Target>;
14 type Error = pyo3::PyErr;
15
16 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
17 use pyo3::prelude::*;
18 let d = self.0.into_pyobject(py)?;
19
20 let m = py.import("debian.deb822")?;
21 let cls = m.getattr("Sources")?;
22
23 cls.call1((d,))
24 }
25}
26
27#[cfg(feature = "python-debian")]
28impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Source {
29 type Target = pyo3::PyAny;
30 type Output = pyo3::Bound<'py, Self::Target>;
31 type Error = pyo3::PyErr;
32
33 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
34 use pyo3::prelude::*;
35 let d = (&self.0).into_pyobject(py)?;
36
37 let m = py.import("debian.deb822")?;
38 let cls = m.getattr("Sources")?;
39
40 cls.call1((d,))
41 }
42}
43
44#[cfg(feature = "python-debian")]
45impl pyo3::FromPyObject<'_> for Source {
46 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
47 use pyo3::prelude::*;
48 Ok(Source(ob.extract()?))
49 }
50}
51
52impl From<deb822_lossless::Paragraph> for Source {
53 fn from(paragraph: deb822_lossless::Paragraph) -> Self {
54 Self(paragraph)
55 }
56}
57
58impl Default for Source {
59 fn default() -> Self {
60 Self(deb822_lossless::Paragraph::new())
61 }
62}
63
64impl Source {
65 pub fn new() -> Self {
67 Self(deb822_lossless::Paragraph::new())
68 }
69
70 pub fn package(&self) -> Option<String> {
72 self.0.get("Package").map(|s| s.to_string())
73 }
74
75 pub fn set_package(&mut self, package: &str) {
77 self.0.set("Package", package);
78 }
79
80 pub fn version(&self) -> Option<debversion::Version> {
82 self.0.get("Version").map(|s| s.parse().unwrap())
83 }
84
85 pub fn set_version(&mut self, version: debversion::Version) {
87 self.0.set("Version", &version.to_string());
88 }
89
90 pub fn maintainer(&self) -> Option<String> {
92 self.0.get("Maintainer").map(|s| s.to_string())
93 }
94
95 pub fn set_maintainer(&mut self, maintainer: &str) {
97 self.0.set("Maintainer", maintainer);
98 }
99
100 pub fn uploaders(&self) -> Option<Vec<String>> {
102 self.0.get("Uploaders").map(|s| {
103 s.split(',')
104 .map(|s| s.trim().to_string())
105 .collect::<Vec<String>>()
106 })
107 }
108
109 pub fn set_uploaders(&mut self, uploaders: Vec<String>) {
111 self.0.set("Uploaders", &uploaders.join(", "));
112 }
113
114 pub fn standards_version(&self) -> Option<String> {
116 self.0.get("Standards-Version").map(|s| s.to_string())
117 }
118
119 pub fn set_standards_version(&mut self, version: &str) {
121 self.0.set("Standards-Version", version);
122 }
123
124 pub fn format(&self) -> Option<String> {
126 self.0.get("Format").map(|s| s.to_string())
127 }
128
129 pub fn set_format(&mut self, format: &str) {
131 self.0.set("Format", format);
132 }
133
134 pub fn vcs_browser(&self) -> Option<String> {
136 self.0.get("Vcs-Browser").map(|s| s.to_string())
137 }
138
139 pub fn set_vcs_browser(&mut self, url: &str) {
141 self.0.set("Vcs-Browser", url);
142 }
143
144 pub fn vcs_git(&self) -> Option<String> {
146 self.0.get("Vcs-Git").map(|s| s.to_string())
147 }
148
149 pub fn set_vcs_git(&mut self, url: &str) {
151 self.0.set("Vcs-Git", url);
152 }
153
154 pub fn vcs_svn(&self) -> Option<String> {
156 self.0.get("Vcs-Svn").map(|s| s.to_string())
157 }
158
159 pub fn set_vcs_svn(&mut self, url: &str) {
161 self.0.set("Vcs-Svn", url);
162 }
163
164 pub fn vcs_hg(&self) -> Option<String> {
166 self.0.get("Vcs-Hg").map(|s| s.to_string())
167 }
168
169 pub fn set_vcs_hg(&mut self, url: &str) {
171 self.0.set("Vcs-Hg", url);
172 }
173
174 pub fn vcs_bzr(&self) -> Option<String> {
176 self.0.get("Vcs-Bzr").map(|s| s.to_string())
177 }
178
179 pub fn set_vcs_bzr(&mut self, url: &str) {
181 self.0.set("Vcs-Bzr", url);
182 }
183
184 pub fn vcs_arch(&self) -> Option<String> {
186 self.0.get("Vcs-Arch").map(|s| s.to_string())
187 }
188
189 pub fn set_vcs_arch(&mut self, url: &str) {
191 self.0.set("Vcs-Arch", url);
192 }
193
194 pub fn vcs_svk(&self) -> Option<String> {
196 self.0.get("Vcs-Svk").map(|s| s.to_string())
197 }
198
199 pub fn set_vcs_svk(&mut self, url: &str) {
201 self.0.set("Vcs-Svk", url);
202 }
203
204 pub fn vcs_darcs(&self) -> Option<String> {
206 self.0.get("Vcs-Darcs").map(|s| s.to_string())
207 }
208
209 pub fn set_vcs_darcs(&mut self, url: &str) {
211 self.0.set("Vcs-Darcs", url);
212 }
213
214 pub fn vcs_mtn(&self) -> Option<String> {
216 self.0.get("Vcs-Mtn").map(|s| s.to_string())
217 }
218
219 pub fn set_vcs_mtn(&mut self, url: &str) {
221 self.0.set("Vcs-Mtn", url);
222 }
223
224 pub fn vcs_cvs(&self) -> Option<String> {
226 self.0.get("Vcs-Cvs").map(|s| s.to_string())
227 }
228
229 pub fn set_vcs_cvs(&mut self, url: &str) {
231 self.0.set("Vcs-Cvs", url);
232 }
233
234 pub fn build_depends(&self) -> Option<Relations> {
236 self.0.get("Build-Depends").map(|s| s.parse().unwrap())
237 }
238
239 pub fn set_build_depends(&mut self, relations: Relations) {
241 self.0.set("Build-Depends", relations.to_string().as_str());
242 }
243
244 pub fn build_depends_indep(&self) -> Option<Relations> {
246 self.0
247 .get("Build-Depends-Indep")
248 .map(|s| s.parse().unwrap())
249 }
250
251 pub fn set_build_depends_indep(&mut self, relations: Relations) {
253 self.0.set("Build-Depends-Indep", &relations.to_string());
254 }
255
256 pub fn build_depends_arch(&self) -> Option<Relations> {
258 self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap())
259 }
260
261 pub fn set_build_depends_arch(&mut self, relations: Relations) {
263 self.0.set("Build-Depends-Arch", &relations.to_string());
264 }
265
266 pub fn build_conflicts(&self) -> Option<Relations> {
268 self.0.get("Build-Conflicts").map(|s| s.parse().unwrap())
269 }
270
271 pub fn set_build_conflicts(&mut self, relations: Relations) {
273 self.0.set("Build-Conflicts", &relations.to_string());
274 }
275
276 pub fn build_conflicts_indep(&self) -> Option<Relations> {
278 self.0
279 .get("Build-Conflicts-Indep")
280 .map(|s| s.parse().unwrap())
281 }
282
283 pub fn set_build_conflicts_indep(&mut self, relations: Relations) {
285 self.0.set("Build-Conflicts-Indep", &relations.to_string());
286 }
287
288 pub fn build_conflicts_arch(&self) -> Option<Relations> {
290 self.0
291 .get("Build-Conflicts-Arch")
292 .map(|s| s.parse().unwrap())
293 }
294
295 pub fn set_build_conflicts_arch(&mut self, relations: Relations) {
297 self.0.set("Build-Conflicts-Arch", &relations.to_string());
298 }
299
300 pub fn binary(&self) -> Option<Relations> {
302 self.0.get("Binary").map(|s| s.parse().unwrap())
303 }
304
305 pub fn set_binary(&mut self, relations: Relations) {
307 self.0.set("Binary", &relations.to_string());
308 }
309
310 pub fn homepage(&self) -> Option<String> {
312 self.0.get("Homepage").map(|s| s.to_string())
313 }
314
315 pub fn set_homepage(&mut self, url: &str) {
317 self.0.set("Homepage", url);
318 }
319
320 pub fn section(&self) -> Option<String> {
322 self.0.get("Section").map(|s| s.to_string())
323 }
324
325 pub fn set_section(&mut self, section: &str) {
327 self.0.set("Section", section);
328 }
329
330 pub fn priority(&self) -> Option<Priority> {
332 self.0.get("Priority").and_then(|v| v.parse().ok())
333 }
334
335 pub fn set_priority(&mut self, priority: Priority) {
337 self.0.set("Priority", priority.to_string().as_str());
338 }
339
340 pub fn architecture(&self) -> Option<String> {
342 self.0.get("Architecture")
343 }
344
345 pub fn set_architecture(&mut self, arch: &str) {
347 self.0.set("Architecture", arch);
348 }
349
350 pub fn directory(&self) -> Option<String> {
352 self.0.get("Directory").map(|s| s.to_string())
353 }
354
355 pub fn set_directory(&mut self, dir: &str) {
357 self.0.set("Directory", dir);
358 }
359
360 pub fn testsuite(&self) -> Option<String> {
362 self.0.get("Testsuite").map(|s| s.to_string())
363 }
364
365 pub fn set_testsuite(&mut self, testsuite: &str) {
367 self.0.set("Testsuite", testsuite);
368 }
369
370 pub fn files(&self) -> Vec<Md5Checksum> {
372 self.0
373 .get("Files")
374 .map(|s| {
375 s.lines()
376 .map(|line| line.parse().unwrap())
377 .collect::<Vec<Md5Checksum>>()
378 })
379 .unwrap_or_default()
380 }
381
382 pub fn set_files(&mut self, files: Vec<Md5Checksum>) {
384 self.0.set(
385 "Files",
386 &files
387 .iter()
388 .map(|f| f.to_string())
389 .collect::<Vec<String>>()
390 .join("\n"),
391 );
392 }
393
394 pub fn checksums_sha1(&self) -> Vec<Sha1Checksum> {
396 self.0
397 .get("Checksums-Sha1")
398 .map(|s| {
399 s.lines()
400 .map(|line| line.parse().unwrap())
401 .collect::<Vec<Sha1Checksum>>()
402 })
403 .unwrap_or_default()
404 }
405
406 pub fn set_checksums_sha1(&mut self, checksums: Vec<Sha1Checksum>) {
408 self.0.set(
409 "Checksums-Sha1",
410 &checksums
411 .iter()
412 .map(|c| c.to_string())
413 .collect::<Vec<String>>()
414 .join("\n"),
415 );
416 }
417
418 pub fn checksums_sha256(&self) -> Vec<Sha256Checksum> {
420 self.0
421 .get("Checksums-Sha256")
422 .map(|s| {
423 s.lines()
424 .map(|line| line.parse().unwrap())
425 .collect::<Vec<Sha256Checksum>>()
426 })
427 .unwrap_or_default()
428 }
429
430 pub fn set_checksums_sha256(&mut self, checksums: Vec<Sha256Checksum>) {
432 self.0.set(
433 "Checksums-Sha256",
434 &checksums
435 .iter()
436 .map(|c| c.to_string())
437 .collect::<Vec<String>>()
438 .join("\n"),
439 );
440 }
441
442 pub fn checksums_sha512(&self) -> Vec<Sha512Checksum> {
444 self.0
445 .get("Checksums-Sha512")
446 .map(|s| {
447 s.lines()
448 .map(|line| line.parse().unwrap())
449 .collect::<Vec<Sha512Checksum>>()
450 })
451 .unwrap_or_default()
452 }
453
454 pub fn set_checksums_sha512(&mut self, checksums: Vec<Sha512Checksum>) {
456 self.0.set(
457 "Checksums-Sha512",
458 &checksums
459 .iter()
460 .map(|c| c.to_string())
461 .collect::<Vec<String>>()
462 .join("\n"),
463 );
464 }
465}
466
467impl std::str::FromStr for Source {
468 type Err = deb822_lossless::ParseError;
469
470 fn from_str(s: &str) -> Result<Self, Self::Err> {
471 Ok(Self(s.parse()?))
472 }
473}
474
475pub struct Package(deb822_lossless::Paragraph);
477
478#[cfg(feature = "python-debian")]
479impl<'py> pyo3::IntoPyObject<'py> for Package {
480 type Target = pyo3::PyAny;
481 type Output = pyo3::Bound<'py, Self::Target>;
482 type Error = pyo3::PyErr;
483
484 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
485 use pyo3::prelude::*;
486 let d = self.0.into_pyobject(py)?;
487
488 let m = py.import("debian.deb822")?;
489 let cls = m.getattr("Packages")?;
490
491 cls.call1((d,))
492 }
493}
494
495#[cfg(feature = "python-debian")]
496impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Package {
497 type Target = pyo3::PyAny;
498 type Output = pyo3::Bound<'py, Self::Target>;
499 type Error = pyo3::PyErr;
500
501 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
502 use pyo3::prelude::*;
503 let d = (&self.0).into_pyobject(py)?;
504
505 let m = py.import("debian.deb822")?;
506 let cls = m.getattr("Packages")?;
507
508 cls.call1((d,))
509 }
510}
511
512#[cfg(feature = "python-debian")]
513impl pyo3::FromPyObject<'_> for Package {
514 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
515 use pyo3::prelude::*;
516 Ok(Package(ob.extract()?))
517 }
518}
519
520impl Package {
521 pub fn new(paragraph: deb822_lossless::Paragraph) -> Self {
523 Self(paragraph)
524 }
525
526 pub fn name(&self) -> Option<String> {
528 self.0.get("Package").map(|s| s.to_string())
529 }
530
531 pub fn set_name(&mut self, name: &str) {
533 self.0.set("Package", name);
534 }
535
536 pub fn version(&self) -> Option<debversion::Version> {
538 self.0.get("Version").map(|s| s.parse().unwrap())
539 }
540
541 pub fn set_version(&mut self, version: debversion::Version) {
543 self.0.set("Version", &version.to_string());
544 }
545
546 pub fn installed_size(&self) -> Option<usize> {
548 self.0.get("Installed-Size").map(|s| s.parse().unwrap())
549 }
550
551 pub fn set_installed_size(&mut self, size: usize) {
553 self.0.set("Installed-Size", &size.to_string());
554 }
555
556 pub fn maintainer(&self) -> Option<String> {
558 self.0.get("Maintainer").map(|s| s.to_string())
559 }
560
561 pub fn set_maintainer(&mut self, maintainer: &str) {
563 self.0.set("Maintainer", maintainer);
564 }
565
566 pub fn architecture(&self) -> Option<String> {
568 self.0.get("Architecture").map(|s| s.to_string())
569 }
570
571 pub fn set_architecture(&mut self, arch: &str) {
573 self.0.set("Architecture", arch);
574 }
575
576 pub fn depends(&self) -> Option<Relations> {
578 self.0.get("Depends").map(|s| s.parse().unwrap())
579 }
580
581 pub fn set_depends(&mut self, relations: Relations) {
583 self.0.set("Depends", &relations.to_string());
584 }
585
586 pub fn recommends(&self) -> Option<Relations> {
588 self.0.get("Recommends").map(|s| s.parse().unwrap())
589 }
590
591 pub fn set_recommends(&mut self, relations: Relations) {
593 self.0.set("Recommends", &relations.to_string());
594 }
595
596 pub fn suggests(&self) -> Option<Relations> {
598 self.0.get("Suggests").map(|s| s.parse().unwrap())
599 }
600
601 pub fn set_suggests(&mut self, relations: Relations) {
603 self.0.set("Suggests", &relations.to_string());
604 }
605
606 pub fn enhances(&self) -> Option<Relations> {
608 self.0.get("Enhances").map(|s| s.parse().unwrap())
609 }
610
611 pub fn set_enhances(&mut self, relations: Relations) {
613 self.0.set("Enhances", &relations.to_string());
614 }
615
616 pub fn pre_depends(&self) -> Option<Relations> {
618 self.0.get("Pre-Depends").map(|s| s.parse().unwrap())
619 }
620
621 pub fn set_pre_depends(&mut self, relations: Relations) {
623 self.0.set("Pre-Depends", &relations.to_string());
624 }
625
626 pub fn breaks(&self) -> Option<Relations> {
628 self.0.get("Breaks").map(|s| s.parse().unwrap())
629 }
630
631 pub fn set_breaks(&mut self, relations: Relations) {
633 self.0.set("Breaks", &relations.to_string());
634 }
635
636 pub fn conflicts(&self) -> Option<Relations> {
638 self.0.get("Conflicts").map(|s| s.parse().unwrap())
639 }
640
641 pub fn set_conflicts(&mut self, relations: Relations) {
643 self.0.set("Conflicts", &relations.to_string());
644 }
645
646 pub fn replaces(&self) -> Option<Relations> {
648 self.0.get("Replaces").map(|s| s.parse().unwrap())
649 }
650
651 pub fn set_replaces(&mut self, relations: Relations) {
653 self.0.set("Replaces", &relations.to_string());
654 }
655
656 pub fn provides(&self) -> Option<Relations> {
658 self.0.get("Provides").map(|s| s.parse().unwrap())
659 }
660
661 pub fn set_provides(&mut self, relations: Relations) {
663 self.0.set("Provides", &relations.to_string());
664 }
665
666 pub fn section(&self) -> Option<String> {
668 self.0.get("Section").map(|s| s.to_string())
669 }
670
671 pub fn set_section(&mut self, section: &str) {
673 self.0.set("Section", section);
674 }
675
676 pub fn priority(&self) -> Option<Priority> {
678 self.0.get("Priority").and_then(|v| v.parse().ok())
679 }
680
681 pub fn set_priority(&mut self, priority: Priority) {
683 self.0.set("Priority", priority.to_string().as_str());
684 }
685
686 pub fn description(&self) -> Option<String> {
688 self.0.get("Description").map(|s| s.to_string())
689 }
690
691 pub fn set_description(&mut self, description: &str) {
693 self.0.set("Description", description);
694 }
695
696 pub fn homepage(&self) -> Option<url::Url> {
698 self.0.get("Homepage").map(|s| s.parse().unwrap())
699 }
700
701 pub fn set_homepage(&mut self, url: &url::Url) {
703 self.0.set("Homepage", url.as_ref());
704 }
705
706 pub fn source(&self) -> Option<String> {
708 self.0.get("Source").map(|s| s.to_string())
709 }
710
711 pub fn set_source(&mut self, source: &str) {
713 self.0.set("Source", source);
714 }
715
716 pub fn description_md5(&self) -> Option<String> {
718 self.0.get("Description-md5").map(|s| s.to_string())
719 }
720
721 pub fn set_description_md5(&mut self, md5: &str) {
723 self.0.set("Description-md5", md5);
724 }
725
726 pub fn tags(&self, tag: &str) -> Option<Vec<String>> {
728 self.0
729 .get(tag)
730 .map(|s| s.split(',').map(|s| s.trim().to_string()).collect())
731 }
732
733 pub fn set_tags(&mut self, tag: &str, tags: Vec<String>) {
735 self.0.set(tag, &tags.join(", "));
736 }
737
738 pub fn filename(&self) -> Option<String> {
740 self.0.get("Filename").map(|s| s.to_string())
741 }
742
743 pub fn set_filename(&mut self, filename: &str) {
745 self.0.set("Filename", filename);
746 }
747
748 pub fn size(&self) -> Option<usize> {
750 self.0.get("Size").map(|s| s.parse().unwrap())
751 }
752
753 pub fn set_size(&mut self, size: usize) {
755 self.0.set("Size", &size.to_string());
756 }
757
758 pub fn md5sum(&self) -> Option<String> {
760 self.0.get("MD5sum").map(|s| s.to_string())
761 }
762
763 pub fn set_md5sum(&mut self, md5sum: &str) {
765 self.0.set("MD5sum", md5sum);
766 }
767
768 pub fn sha256(&self) -> Option<String> {
770 self.0.get("SHA256").map(|s| s.to_string())
771 }
772
773 pub fn set_sha256(&mut self, sha256: &str) {
775 self.0.set("SHA256", sha256);
776 }
777
778 pub fn multi_arch(&self) -> Option<MultiArch> {
780 self.0.get("Multi-Arch").map(|s| s.parse().unwrap())
781 }
782
783 pub fn set_multi_arch(&mut self, arch: MultiArch) {
785 self.0.set("Multi-Arch", arch.to_string().as_str());
786 }
787}
788
789impl std::str::FromStr for Package {
790 type Err = deb822_lossless::ParseError;
791
792 fn from_str(s: &str) -> Result<Self, Self::Err> {
793 Ok(Self(s.parse()?))
794 }
795}
796
797pub struct Release(deb822_lossless::Paragraph);
799
800#[cfg(feature = "python-debian")]
801impl<'py> pyo3::IntoPyObject<'py> for Release {
802 type Target = pyo3::PyAny;
803 type Output = pyo3::Bound<'py, Self::Target>;
804 type Error = pyo3::PyErr;
805
806 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
807 use pyo3::prelude::*;
808 let d = self.0.into_pyobject(py)?;
809
810 let m = py.import("debian.deb822")?;
811 let cls = m.getattr("Release")?;
812
813 cls.call1((d,))
814 }
815}
816
817#[cfg(feature = "python-debian")]
818impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Release {
819 type Target = pyo3::PyAny;
820 type Output = pyo3::Bound<'py, Self::Target>;
821 type Error = pyo3::PyErr;
822
823 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
824 use pyo3::prelude::*;
825 let d = (&self.0).into_pyobject(py)?;
826
827 let m = py.import("debian.deb822")?;
828 let cls = m.getattr("Release")?;
829
830 cls.call1((d,))
831 }
832}
833
834#[cfg(feature = "python-debian")]
835impl pyo3::FromPyObject<'_> for Release {
836 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
837 use pyo3::prelude::*;
838 Ok(Release(ob.extract()?))
839 }
840}
841
842impl Release {
843 pub fn new(paragraph: deb822_lossless::Paragraph) -> Self {
845 Self(paragraph)
846 }
847
848 pub fn origin(&self) -> Option<String> {
850 self.0.get("Origin").map(|s| s.to_string())
851 }
852
853 pub fn set_origin(&mut self, origin: &str) {
855 self.0.set("Origin", origin);
856 }
857
858 pub fn label(&self) -> Option<String> {
860 self.0.get("Label").map(|s| s.to_string())
861 }
862
863 pub fn set_label(&mut self, label: &str) {
865 self.0.set("Label", label);
866 }
867
868 pub fn suite(&self) -> Option<String> {
870 self.0.get("Suite").map(|s| s.to_string())
871 }
872
873 pub fn set_suite(&mut self, suite: &str) {
875 self.0.set("Suite", suite);
876 }
877
878 pub fn codename(&self) -> Option<String> {
880 self.0.get("Codename").map(|s| s.to_string())
881 }
882
883 pub fn set_codename(&mut self, codename: &str) {
885 self.0.set("Codename", codename);
886 }
887
888 pub fn changelogs(&self) -> Option<Vec<String>> {
890 self.0.get("Changelogs").map(|s| {
891 s.split(',')
892 .map(|s| s.trim().to_string())
893 .collect::<Vec<String>>()
894 })
895 }
896
897 pub fn set_changelogs(&mut self, changelogs: Vec<String>) {
899 self.0.set("Changelogs", &changelogs.join(", "));
900 }
901
902 #[cfg(feature = "chrono")]
903 pub fn date(&self) -> Option<chrono::DateTime<chrono::FixedOffset>> {
905 self.0
906 .get("Date")
907 .as_ref()
908 .map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap())
909 }
910
911 #[cfg(feature = "chrono")]
912 pub fn set_date(&mut self, date: chrono::DateTime<chrono::FixedOffset>) {
914 self.0.set("Date", date.to_rfc2822().as_str());
915 }
916
917 #[cfg(feature = "chrono")]
918 pub fn valid_until(&self) -> Option<chrono::DateTime<chrono::FixedOffset>> {
920 self.0
921 .get("Valid-Until")
922 .as_ref()
923 .map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap())
924 }
925
926 #[cfg(feature = "chrono")]
927 pub fn set_valid_until(&mut self, date: chrono::DateTime<chrono::FixedOffset>) {
929 self.0.set("Valid-Until", date.to_rfc2822().as_str());
930 }
931
932 pub fn acquire_by_hash(&self) -> bool {
934 self.0
935 .get("Acquire-By-Hash")
936 .map(|s| s == "yes")
937 .unwrap_or(false)
938 }
939
940 pub fn set_acquire_by_hash(&mut self, acquire_by_hash: bool) {
942 self.0.set(
943 "Acquire-By-Hash",
944 if acquire_by_hash { "yes" } else { "no" },
945 );
946 }
947
948 pub fn no_support_for_architecture_all(&self) -> bool {
950 self.0
951 .get("No-Support-For-Architecture-All")
952 .map(|s| s == "yes")
953 .unwrap_or(false)
954 }
955
956 pub fn set_no_support_for_architecture_all(&mut self, no_support_for_architecture_all: bool) {
958 self.0.set(
959 "No-Support-For-Architecture-All",
960 if no_support_for_architecture_all {
961 "yes"
962 } else {
963 "no"
964 },
965 );
966 }
967
968 pub fn architectures(&self) -> Option<Vec<String>> {
970 self.0.get("Architectures").map(|s| {
971 s.split_whitespace()
972 .map(|s| s.trim().to_string())
973 .collect::<Vec<String>>()
974 })
975 }
976
977 pub fn set_architectures(&mut self, architectures: Vec<String>) {
979 self.0.set("Architectures", &architectures.join(" "));
980 }
981
982 pub fn components(&self) -> Option<Vec<String>> {
984 self.0.get("Components").map(|s| {
985 s.split_whitespace()
986 .map(|s| s.trim().to_string())
987 .collect::<Vec<String>>()
988 })
989 }
990
991 pub fn set_components(&mut self, components: Vec<String>) {
993 self.0.set("Components", &components.join(" "));
994 }
995
996 pub fn description(&self) -> Option<String> {
998 self.0.get("Description").map(|s| s.to_string())
999 }
1000
1001 pub fn set_description(&mut self, description: &str) {
1003 self.0.set("Description", description);
1004 }
1005
1006 pub fn checksums_md5(&self) -> Vec<Md5Checksum> {
1008 self.0
1009 .get("MD5Sum")
1010 .map(|s| {
1011 s.lines()
1012 .map(|line| line.parse().unwrap())
1013 .collect::<Vec<Md5Checksum>>()
1014 })
1015 .unwrap_or_default()
1016 }
1017
1018 pub fn set_checksums_md5(&mut self, files: Vec<Md5Checksum>) {
1020 self.0.set(
1021 "MD5Sum",
1022 &files
1023 .iter()
1024 .map(|f| f.to_string())
1025 .collect::<Vec<String>>()
1026 .join("\n"),
1027 );
1028 }
1029
1030 pub fn checksums_sha1(&self) -> Vec<Sha1Checksum> {
1032 self.0
1033 .get("SHA1")
1034 .map(|s| {
1035 s.lines()
1036 .map(|line| line.parse().unwrap())
1037 .collect::<Vec<Sha1Checksum>>()
1038 })
1039 .unwrap_or_default()
1040 }
1041
1042 pub fn set_checksums_sha1(&mut self, checksums: Vec<Sha1Checksum>) {
1044 self.0.set(
1045 "SHA1",
1046 &checksums
1047 .iter()
1048 .map(|c| c.to_string())
1049 .collect::<Vec<String>>()
1050 .join("\n"),
1051 );
1052 }
1053
1054 pub fn checksums_sha256(&self) -> Vec<Sha256Checksum> {
1056 self.0
1057 .get("SHA256")
1058 .map(|s| {
1059 s.lines()
1060 .map(|line| line.parse().unwrap())
1061 .collect::<Vec<Sha256Checksum>>()
1062 })
1063 .unwrap_or_default()
1064 }
1065
1066 pub fn set_checksums_sha256(&mut self, checksums: Vec<Sha256Checksum>) {
1068 self.0.set(
1069 "SHA256",
1070 &checksums
1071 .iter()
1072 .map(|c| c.to_string())
1073 .collect::<Vec<String>>()
1074 .join("\n"),
1075 );
1076 }
1077
1078 pub fn checksums_sha512(&self) -> Vec<Sha512Checksum> {
1080 self.0
1081 .get("SHA512")
1082 .map(|s| {
1083 s.lines()
1084 .map(|line| line.parse().unwrap())
1085 .collect::<Vec<Sha512Checksum>>()
1086 })
1087 .unwrap_or_default()
1088 }
1089
1090 pub fn set_checksums_sha512(&mut self, checksums: Vec<Sha512Checksum>) {
1092 self.0.set(
1093 "SHA512",
1094 &checksums
1095 .iter()
1096 .map(|c| c.to_string())
1097 .collect::<Vec<String>>()
1098 .join("\n"),
1099 );
1100 }
1101}
1102
1103impl std::str::FromStr for Release {
1104 type Err = deb822_lossless::ParseError;
1105
1106 fn from_str(s: &str) -> Result<Self, Self::Err> {
1107 Ok(Self(s.parse()?))
1108 }
1109}
1110
1111#[cfg(test)]
1112mod tests {
1113 use super::*;
1114 use crate::fields::PackageListEntry;
1115
1116 #[test]
1117 fn test_parse_package_list() {
1118 let s = "package1 binary section standard extra1=foo extra2=bar";
1119 let p: PackageListEntry = s.parse().unwrap();
1120 assert_eq!(p.package, "package1");
1121 assert_eq!(p.package_type, "binary");
1122 assert_eq!(p.section, "section");
1123 assert_eq!(p.priority, super::Priority::Standard);
1124 assert_eq!(p.extra.get("extra1"), Some(&"foo".to_string()));
1125 assert_eq!(p.extra.get("extra2"), Some(&"bar".to_string()));
1126 }
1127
1128 #[test]
1129 fn test_parse_package_list_no_extra() {
1130 let s = "package1 binary section standard";
1131 let p: PackageListEntry = s.parse().unwrap();
1132 assert_eq!(p.package, "package1");
1133 assert_eq!(p.package_type, "binary");
1134 assert_eq!(p.section, "section");
1135 assert_eq!(p.priority, super::Priority::Standard);
1136 assert!(p.extra.is_empty());
1137 }
1138
1139 #[test]
1140 fn test_files() {
1141 let s = "md5sum 1234 filename";
1142 let f: super::Md5Checksum = s.parse().unwrap();
1143 assert_eq!(f.md5sum, "md5sum");
1144 assert_eq!(f.size, 1234);
1145 assert_eq!(f.filename, "filename");
1146 }
1147
1148 #[test]
1149 fn test_sha1_checksum() {
1150 let s = "sha1 1234 filename";
1151 let f: super::Sha1Checksum = s.parse().unwrap();
1152 assert_eq!(f.sha1, "sha1");
1153 assert_eq!(f.size, 1234);
1154 assert_eq!(f.filename, "filename");
1155 }
1156
1157 #[test]
1158 fn test_sha256_checksum() {
1159 let s = "sha256 1234 filename";
1160 let f: super::Sha256Checksum = s.parse().unwrap();
1161 assert_eq!(f.sha256, "sha256");
1162 assert_eq!(f.size, 1234);
1163 assert_eq!(f.filename, "filename");
1164 }
1165
1166 #[test]
1167 fn test_sha512_checksum() {
1168 let s = "sha512 1234 filename";
1169 let f: super::Sha512Checksum = s.parse().unwrap();
1170 assert_eq!(f.sha512, "sha512");
1171 assert_eq!(f.size, 1234);
1172 assert_eq!(f.filename, "filename");
1173 }
1174
1175 #[test]
1176 fn test_source() {
1177 let s = r#"Package: foo
1178Version: 1.0
1179Maintainer: John Doe <john@example.com>
1180Uploaders: Jane Doe <jane@example.com>
1181Standards-Version: 3.9.8
1182Format: 3.0 (quilt)
1183Vcs-Browser: https://example.com/foo
1184Vcs-Git: https://example.com/foo.git
1185Build-Depends: debhelper (>= 9)
1186Build-Depends-Indep: python
1187Build-Depends-Arch: gcc
1188Build-Conflicts: bar
1189Build-Conflicts-Indep: python
1190Build-Conflicts-Arch: gcc
1191Binary: foo, bar
1192Homepage: https://example.com/foo
1193Section: devel
1194Priority: optional
1195Architecture: any
1196Directory: pool/main/f/foo
1197Files:
1198 25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz
1199Checksums-Sha1:
1200 b72b5fae3b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz
1201"#;
1202 let p: super::Source = s.parse().unwrap();
1203 assert_eq!(p.package(), Some("foo".to_string()));
1204 assert_eq!(p.version(), Some("1.0".parse().unwrap()));
1205 assert_eq!(
1206 p.maintainer(),
1207 Some("John Doe <john@example.com>".to_string())
1208 );
1209 assert_eq!(
1210 p.uploaders(),
1211 Some(vec!["Jane Doe <jane@example.com>".to_string()])
1212 );
1213 assert_eq!(p.standards_version(), Some("3.9.8".to_string()));
1214 assert_eq!(p.format(), Some("3.0 (quilt)".to_string()));
1215 assert_eq!(p.vcs_browser(), Some("https://example.com/foo".to_string()));
1216 assert_eq!(p.vcs_git(), Some("https://example.com/foo.git".to_string()));
1217 assert_eq!(
1218 p.build_depends_indep().map(|x| x.to_string()),
1219 Some("python".parse().unwrap())
1220 );
1221 assert_eq!(p.build_depends(), Some("debhelper (>= 9)".parse().unwrap()));
1222 assert_eq!(p.build_depends_arch(), Some("gcc".parse().unwrap()));
1223 assert_eq!(p.build_conflicts(), Some("bar".parse().unwrap()));
1224 assert_eq!(p.build_conflicts_indep(), Some("python".parse().unwrap()));
1225 assert_eq!(p.build_conflicts_arch(), Some("gcc".parse().unwrap()));
1226 assert_eq!(p.binary(), Some("foo, bar".parse().unwrap()));
1227 assert_eq!(p.homepage(), Some("https://example.com/foo".to_string()));
1228 assert_eq!(p.section(), Some("devel".to_string()));
1229 assert_eq!(p.priority(), Some(super::Priority::Optional));
1230 assert_eq!(p.architecture(), Some("any".to_string()));
1231 assert_eq!(p.directory(), Some("pool/main/f/foo".to_string()));
1232 assert_eq!(p.files().len(), 1);
1233 assert_eq!(
1234 p.files()[0].md5sum,
1235 "25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3".to_string()
1236 );
1237 assert_eq!(p.files()[0].size, 1234);
1238 assert_eq!(p.files()[0].filename, "foo_1.0.tar.gz".to_string());
1239 assert_eq!(p.checksums_sha1().len(), 1);
1240 assert_eq!(
1241 p.checksums_sha1()[0].sha1,
1242 "b72b5fae3b3b3b3b3b3b3b3b3b3b3b3".to_string()
1243 );
1244 }
1245
1246 #[test]
1247 fn test_package() {
1248 let s = r#"Package: foo
1249Version: 1.0
1250Source: bar
1251Maintainer: John Doe <john@example.com>
1252Architecture: any
1253Depends: bar
1254Recommends: baz
1255Suggests: qux
1256Enhances: quux
1257Pre-Depends: quuz
1258Breaks: corge
1259Conflicts: grault
1260Replaces: garply
1261Provides: waldo
1262Section: devel
1263Priority: optional
1264Description: Foo is a bar
1265Homepage: https://example.com/foo
1266Description-md5: 1234
1267Tags: foo, bar
1268Filename: pool/main/f/foo/foo_1.0.deb
1269Size: 1234
1270Installed-Size: 1234
1271MD5sum: 1234
1272SHA256: 1234
1273Multi-Arch: same
1274"#;
1275 let p: super::Package = s.parse().unwrap();
1276 assert_eq!(p.name(), Some("foo".to_string()));
1277 assert_eq!(p.version(), Some("1.0".parse().unwrap()));
1278 assert_eq!(p.source(), Some("bar".to_string()));
1279 assert_eq!(
1280 p.maintainer(),
1281 Some("John Doe <john@example.com>".to_string())
1282 );
1283 assert_eq!(p.architecture(), Some("any".to_string()));
1284 assert_eq!(p.depends(), Some("bar".parse().unwrap()));
1285 assert_eq!(p.recommends(), Some("baz".parse().unwrap()));
1286 assert_eq!(p.suggests(), Some("qux".parse().unwrap()));
1287 assert_eq!(p.enhances(), Some("quux".parse().unwrap()));
1288 assert_eq!(p.pre_depends(), Some("quuz".parse().unwrap()));
1289 assert_eq!(p.breaks(), Some("corge".parse().unwrap()));
1290 assert_eq!(p.conflicts(), Some("grault".parse().unwrap()));
1291 assert_eq!(p.replaces(), Some("garply".parse().unwrap()));
1292 assert_eq!(p.provides(), Some("waldo".parse().unwrap()));
1293 assert_eq!(p.section(), Some("devel".to_string()));
1294 assert_eq!(p.priority(), Some(super::Priority::Optional));
1295 assert_eq!(p.description(), Some("Foo is a bar".to_string()));
1296 assert_eq!(
1297 p.homepage(),
1298 Some(url::Url::parse("https://example.com/foo").unwrap())
1299 );
1300 assert_eq!(p.description_md5(), Some("1234".to_string()));
1301 assert_eq!(
1302 p.tags("Tags"),
1303 Some(vec!["foo".to_string(), "bar".to_string()])
1304 );
1305 assert_eq!(
1306 p.filename(),
1307 Some("pool/main/f/foo/foo_1.0.deb".to_string())
1308 );
1309 assert_eq!(p.size(), Some(1234));
1310 assert_eq!(p.installed_size(), Some(1234));
1311 assert_eq!(p.md5sum(), Some("1234".to_string()));
1312 assert_eq!(p.sha256(), Some("1234".to_string()));
1313 assert_eq!(p.multi_arch(), Some(MultiArch::Same));
1314 }
1315
1316 #[test]
1317 fn test_release() {
1318 let s = include_str!("../testdata/Release");
1319 let release: super::Release = s.parse().unwrap();
1320
1321 assert_eq!(release.origin(), Some("Debian".to_string()));
1322 assert_eq!(release.label(), Some("Debian".to_string()));
1323 assert_eq!(release.suite(), Some("testing".to_string()));
1324 assert_eq!(
1325 release.architectures(),
1326 vec![
1327 "all".to_string(),
1328 "amd64".to_string(),
1329 "arm64".to_string(),
1330 "armel".to_string(),
1331 "armhf".to_string()
1332 ]
1333 .into()
1334 );
1335 assert_eq!(
1336 release.components(),
1337 vec![
1338 "main".to_string(),
1339 "contrib".to_string(),
1340 "non-free-firmware".to_string(),
1341 "non-free".to_string()
1342 ]
1343 .into()
1344 );
1345 assert_eq!(
1346 release.description(),
1347 Some("Debian x.y Testing distribution - Not Released".to_string())
1348 );
1349 assert_eq!(318, release.checksums_md5().len());
1350 }
1351}