alpm_buildinfo/build_info/
v2.rs1use std::{
2 fmt::{Display, Formatter},
3 str::FromStr,
4};
5
6use alpm_types::{
7 Architecture,
8 BuildDate,
9 BuildDirectory,
10 BuildEnvironmentOption,
11 BuildTool,
12 BuildToolVersion,
13 Checksum,
14 FullVersion,
15 InstalledPackage,
16 Name,
17 PackageOption,
18 Packager,
19 SchemaVersion,
20 StartDirectory,
21 digests::Sha256,
22 semver_version::Version as SemverVersion,
23};
24use serde_with::{DisplayFromStr, serde_as};
25
26use crate::{BuildInfoSchema, Error, build_info::format::BuildInfoFormat};
27
28#[serde_as]
67#[derive(Clone, Debug, serde::Deserialize, PartialEq, serde_more::SerializeMore)]
68#[more(key = "format", position = "front")]
69pub struct BuildInfoV2 {
70 #[serde_as(as = "DisplayFromStr")]
72 pub pkgname: Name,
73
74 #[serde_as(as = "DisplayFromStr")]
76 pub pkgbase: Name,
77
78 #[serde_as(as = "DisplayFromStr")]
80 pub pkgver: FullVersion,
81
82 #[serde_as(as = "DisplayFromStr")]
84 pub pkgarch: Architecture,
85
86 #[serde_as(as = "DisplayFromStr")]
88 pub pkgbuild_sha256sum: Checksum<Sha256>,
89
90 #[serde_as(as = "DisplayFromStr")]
92 pub packager: Packager,
93
94 #[serde_as(as = "DisplayFromStr")]
96 pub builddate: BuildDate,
97
98 #[serde_as(as = "DisplayFromStr")]
100 pub builddir: BuildDirectory,
101
102 #[serde_as(as = "Vec<DisplayFromStr>")]
104 #[serde(default)]
105 pub buildenv: Vec<BuildEnvironmentOption>,
106
107 #[serde_as(as = "Vec<DisplayFromStr>")]
109 #[serde(default)]
110 pub options: Vec<PackageOption>,
111
112 #[serde_as(as = "Vec<DisplayFromStr>")]
114 #[serde(default)]
115 pub installed: Vec<InstalledPackage>,
116
117 #[serde_as(as = "DisplayFromStr")]
119 pub startdir: StartDirectory,
120
121 #[serde_as(as = "DisplayFromStr")]
123 pub buildtool: BuildTool,
124
125 #[serde_as(as = "DisplayFromStr")]
127 pub buildtoolver: BuildToolVersion,
128}
129
130impl BuildInfoV2 {
131 fn format(&self) -> String {
133 BuildInfoSchema::V2(SchemaVersion::new(SemverVersion::new(2, 0, 0))).to_string()
134 }
135}
136
137impl FromStr for BuildInfoV2 {
138 type Err = Error;
139 fn from_str(input: &str) -> Result<BuildInfoV2, Self::Err> {
146 let build_info_format: BuildInfoFormat = alpm_parsers::custom_ini::from_str(input)?;
147 let schema_version: SchemaVersion = build_info_format.into();
148 if schema_version.inner().major != 2 {
149 return Err(Error::WrongSchemaVersion(schema_version));
150 }
151
152 let buildinfo: BuildInfoV2 = alpm_parsers::custom_ini::from_str(input)?;
153 Ok(buildinfo)
154 }
155}
156
157impl Display for BuildInfoV2 {
158 fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
159 write!(
160 fmt,
161 "format = {}\n\
162 pkgname = {}\n\
163 pkgbase = {}\n\
164 pkgver = {}\n\
165 pkgarch = {}\n\
166 pkgbuild_sha256sum = {}\n\
167 packager = {}\n\
168 builddate = {}\n\
169 builddir = {}\n\
170 startdir = {}\n\
171 buildtool = {}\n\
172 buildtoolver = {}\n\
173 {}\n\
174 {}\n\
175 {}\n\
176 ",
177 self.format(),
178 self.pkgname,
179 self.pkgbase,
180 self.pkgver,
181 self.pkgarch,
182 self.pkgbuild_sha256sum,
183 self.packager,
184 self.builddate,
185 self.builddir,
186 self.startdir,
187 self.buildtool,
188 self.buildtoolver,
189 self.buildenv
190 .iter()
191 .map(|v| format!("buildenv = {v}"))
192 .collect::<Vec<String>>()
193 .join("\n"),
194 self.options
195 .iter()
196 .map(|v| format!("options = {v}"))
197 .collect::<Vec<String>>()
198 .join("\n"),
199 self.installed
200 .iter()
201 .map(|v| format!("installed = {v}"))
202 .collect::<Vec<String>>()
203 .join("\n"),
204 )
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use rstest::rstest;
211 use testresult::TestResult;
212
213 use super::*;
214
215 const VALID_BUILDINFOV2_CASE1: &str = r#"
217format = 2
218builddate = 1
219builddir = /build
220startdir = /startdir/
221buildtool = devtools
222buildtoolver = 1:1.2.1-1-any
223buildenv = ccache
224buildenv = color
225installed = bar-1.2.3-1-any
226installed = beh-2.2.3-4-any
227options = lto
228options = !strip
229packager = Foobar McFooface <foobar@mcfooface.org>
230pkgarch = any
231pkgbase = foo
232pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
233pkgname = foo
234pkgver = 1:1.0.0-1
235"#;
236
237 const VALID_BUILDINFOV2_CASE2: &str = r#"
239format = 2
240builddate = 1
241builddir = /build
242startdir = /startdir/
243buildtool = devtools
244buildtoolver = 1:1.2.1-1-any
245buildenv = ccache
246installed = bar-1.2.3-1-any
247options = lto
248packager = Foobar McFooface <foobar@mcfooface.org>
249pkgarch = any
250pkgbase = foo
251pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
252pkgname = foo
253pkgver = 1:1.0.0-1
254"#;
255
256 const INVALID_BUILDINFOV2: &str = r#"
258format = 1
259builddate = 1
260builddir = /build
261startdir = /startdir/
262buildtool = devtools
263buildtoolver = 1:1.2.1-1-any
264buildenv = ccache
265buildenv = color
266installed = bar-1.2.3-1-any
267installed = beh-2.2.3-4-any
268options = lto
269options = !strip
270packager = Foobar McFooface <foobar@mcfooface.org>
271pkgarch = any
272pkgbase = foo
273pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
274pkgname = foo
275pkgver = 1:1.0.0-1
276"#;
277
278 #[rstest]
279 #[case(VALID_BUILDINFOV2_CASE1)]
280 #[case(VALID_BUILDINFOV2_CASE2)]
281 fn buildinfov2_from_str(#[case] buildinfo: &str) -> TestResult {
282 BuildInfoV2::from_str(buildinfo)?;
283 Ok(())
284 }
285
286 #[rstest]
287 fn buildinfov2() -> TestResult {
288 BuildInfoV2 {
289 builddate: 1,
290 builddir: BuildDirectory::from_str("/build")?,
291 startdir: StartDirectory::from_str("/startdir/")?,
292 buildtool: BuildTool::from_str("devtools")?,
293 buildtoolver: BuildToolVersion::from_str("1:1.2.1-1-any")?,
294 buildenv: vec![BuildEnvironmentOption::new("check")?],
295 installed: vec![InstalledPackage::from_str("bar-1:1.0.0-2-any")?],
296 options: vec![PackageOption::new("lto")?],
297 packager: Packager::from_str("Foobar McFooface <foobar@mcfooface.org>")?,
298 pkgarch: Architecture::Any,
299 pkgbase: Name::new("foo")?,
300 pkgbuild_sha256sum: Checksum::<Sha256>::calculate_from("foo"),
301 pkgname: Name::new("foo")?,
302 pkgver: FullVersion::from_str("1:1.0.0-1")?,
303 };
304 Ok(())
305 }
306
307 #[rstest]
308 fn buildinfov2_invalid_schemaversion() -> TestResult {
309 assert!(BuildInfoV2::from_str(INVALID_BUILDINFOV2).is_err());
310 Ok(())
311 }
312
313 #[rstest]
314 #[case("builddate = 2")]
315 #[case("builddir = /build2")]
316 #[case("startdir = /startdir2/")]
317 #[case("buildtool = devtools2")]
318 #[case("buildtoolver = 1:1.2.1-2-any")]
319 #[case("format = 1")]
320 #[case("packager = Foobar McFooface <foobar@mcfooface.org>")]
321 #[case("pkgarch = any")]
322 #[case("pkgbase = foo")]
323 #[case("pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c")]
324 #[case("pkgname = foo")]
325 #[case("pkgver = 1:1.0.0-1")]
326 fn buildinfov2_from_str_duplicate_fail(#[case] duplicate: &str) {
327 let mut buildinfov2 = VALID_BUILDINFOV2_CASE1.to_string();
328 buildinfov2.push_str(duplicate);
329 assert!(BuildInfoV2::from_str(&buildinfov2).is_err());
330 }
331}