]> git.proxmox.com Git - proxmox-apt.git/blame - src/deb822/packages_file.rs
packages file: add section field
[proxmox-apt.git] / src / deb822 / packages_file.rs
CommitLineData
8cdd2311
FG
1use std::collections::HashMap;
2
3use anyhow::{bail, Error};
4use rfc822_like::de::Deserializer;
5use serde::Deserialize;
6use serde_json::Value;
7
8use super::CheckSums;
9
10#[derive(Debug, Deserialize)]
11#[serde(rename_all = "PascalCase")]
12pub struct PackagesFileRaw {
13 pub package: String,
14 pub source: Option<String>,
15 pub version: String,
16 pub section: String,
17 pub priority: String,
18 pub architecture: String,
19 pub essential: Option<String>,
20 pub depends: Option<String>,
21 pub recommends: Option<String>,
22 pub suggests: Option<String>,
23 pub breaks: Option<String>,
24 pub conflicts: Option<String>,
25 #[serde(rename = "Installed-Size")]
26 pub installed_size: Option<String>,
27 pub maintainer: String,
28 pub description: String,
29 pub filename: String,
30 pub size: String,
31 #[serde(rename = "Multi-Arch")]
32 pub multi_arch: Option<String>,
33
34 #[serde(rename = "MD5sum")]
35 pub md5_sum: Option<String>,
36 #[serde(rename = "SHA1")]
37 pub sha1: Option<String>,
38 #[serde(rename = "SHA256")]
39 pub sha256: Option<String>,
40 #[serde(rename = "SHA512")]
41 pub sha512: Option<String>,
42
43 #[serde(rename = "Description-md5")]
44 pub description_md5: Option<String>,
45
46 #[serde(flatten)]
47 pub extra_fields: HashMap<String, Value>,
48}
49
50#[derive(Debug, PartialEq, Eq)]
51pub struct PackageEntry {
52 pub package: String,
53 pub source: Option<String>,
54 pub version: String,
55 pub architecture: String,
56 pub file: String,
57 pub size: usize,
58 pub installed_size: Option<usize>,
59 pub checksums: CheckSums,
ab6c2c74 60 pub section: String,
8cdd2311
FG
61}
62
63#[derive(Debug, Default, PartialEq, Eq)]
64/// A parsed representation of a Release file
65pub struct PackagesFile {
66 pub files: Vec<PackageEntry>,
67}
68
69impl TryFrom<PackagesFileRaw> for PackageEntry {
70 type Error = Error;
71
72 fn try_from(value: PackagesFileRaw) -> Result<Self, Self::Error> {
73 let installed_size = match value.installed_size {
74 Some(val) => Some(val.parse::<usize>()?),
75 None => None,
76 };
77
78 let mut parsed = PackageEntry {
79 package: value.package,
80 source: value.source,
81 version: value.version,
82 architecture: value.architecture,
83 file: value.filename,
84 size: value.size.parse::<usize>()?,
85 installed_size,
86 checksums: CheckSums::default(),
ab6c2c74 87 section: value.section,
8cdd2311
FG
88 };
89
90 if let Some(md5) = value.md5_sum {
91 let mut bytes = [0u8; 16];
92 hex::decode_to_slice(md5, &mut bytes)?;
93 parsed.checksums.md5 = Some(bytes);
94 };
95
96 if let Some(sha1) = value.sha1 {
97 let mut bytes = [0u8; 20];
98 hex::decode_to_slice(sha1, &mut bytes)?;
99 parsed.checksums.sha1 = Some(bytes);
100 };
101
102 if let Some(sha256) = value.sha256 {
103 let mut bytes = [0u8; 32];
104 hex::decode_to_slice(sha256, &mut bytes)?;
105 parsed.checksums.sha256 = Some(bytes);
106 };
107
108 if let Some(sha512) = value.sha512 {
109 let mut bytes = [0u8; 64];
110 hex::decode_to_slice(sha512, &mut bytes)?;
111 parsed.checksums.sha512 = Some(bytes);
112 };
113
114 if !parsed.checksums.is_secure() {
115 bail!(
116 "no strong checksum found for package entry '{}'",
117 parsed.package
118 );
119 }
120
121 Ok(parsed)
122 }
123}
124
125impl TryFrom<String> for PackagesFile {
126 type Error = Error;
127
128 fn try_from(value: String) -> Result<Self, Self::Error> {
129 value.as_bytes().try_into()
130 }
131}
132
133impl TryFrom<&[u8]> for PackagesFile {
134 type Error = Error;
135
136 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
137 let deserialized = <Vec<PackagesFileRaw>>::deserialize(Deserializer::new(value))?;
138 deserialized.try_into()
139 }
140}
141
142impl TryFrom<Vec<PackagesFileRaw>> for PackagesFile {
143 type Error = Error;
144
145 fn try_from(value: Vec<PackagesFileRaw>) -> Result<Self, Self::Error> {
146 let mut files = Vec::with_capacity(value.len());
147 for entry in value {
148 let entry: PackageEntry = entry.try_into()?;
149 files.push(entry);
150 }
151
152 Ok(Self { files })
153 }
154}
155
156#[test]
157pub fn test_deb_packages_file() {
158 let input = include_str!(concat!(
159 env!("CARGO_MANIFEST_DIR"),
160 "/tests/deb822/packages/deb.debian.org_debian_dists_bullseye_main_binary-amd64_Packages"
161 ));
162
163 let deserialized =
164 <Vec<PackagesFileRaw>>::deserialize(Deserializer::new(input.as_bytes())).unwrap();
165 //println!("{:?}", deserialized);
166
167 let parsed: PackagesFile = deserialized.try_into().unwrap();
168 //println!("{:?}", parsed);
169
170 assert_eq!(parsed.files.len(), 58618);
171}