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