alpm_srcinfo/source_info/v1/package.rs
1//! Handling of metadata found in a `pkgname` section of SRCINFO data.
2use std::collections::BTreeMap;
3
4use alpm_types::{
5 Architecture,
6 Architectures,
7 Backup,
8 Changelog,
9 Install,
10 License,
11 MakepkgOption,
12 Name,
13 OptionalDependency,
14 PackageDescription,
15 PackageRelation,
16 RelationOrSoname,
17 SystemArchitecture,
18 Url,
19};
20use serde::{Deserialize, Serialize};
21
22use crate::{
23 Error,
24 source_info::parser::{
25 ClearableProperty,
26 PackageProperty,
27 RawPackage,
28 RelationProperty,
29 SharedMetaProperty,
30 },
31};
32#[cfg(doc)]
33use crate::{MergedPackage, SourceInfoV1, source_info::v1::package_base::PackageBase};
34
35/// A [`Package`] property that can override its respective defaults in [`PackageBase`].
36///
37/// This type is similar to [`Option`], which has special serialization behavior.
38/// However, in some file formats (e.g. JSON) it is not possible to represent data such as
39/// `Option<Option<T>>`, as serialization would flatten the structure. This type enables
40/// representation of this type of data.
41#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
42#[serde(tag = "override")]
43pub enum Override<T> {
44 /// The property is not overridden.
45 #[default]
46 No,
47 /// The property is cleared.
48 Clear,
49 /// The property is overridden.
50 Yes {
51 /// The value with which the property is overridden.
52 value: T,
53 },
54}
55
56impl<T> Override<T> {
57 /// Applies `self` onto an `Option<T>`.
58 ///
59 /// - `Override::No` -> `other` stays untouched.
60 /// - `Override::Clear` -> `other` is set to `None`.
61 /// - `Override::Yes { value }` -> `other` is set to `Some(value)`.
62 #[inline]
63 pub fn merge_option(self, other: &mut Option<T>) {
64 match self {
65 Override::No => (),
66 Override::Clear => *other = None,
67 Override::Yes { value } => *other = Some(value),
68 }
69 }
70
71 /// If `Override::Yes`, its value will be returned.
72 /// If `self` is something else, `self` will be set to a `Override::Yes { value: default }`.
73 ///
74 /// Similar to as [Option::get_or_insert].
75 #[inline]
76 pub fn get_or_insert(&mut self, default: T) -> &mut T {
77 if let Override::Yes { value } = self {
78 return value;
79 }
80
81 *self = Override::Yes { value: default };
82
83 // This is infallible.
84 if let Override::Yes { value } = self {
85 return value;
86 }
87 unreachable!()
88 }
89}
90
91impl<T> Override<Vec<T>> {
92 /// Applies `self` onto an `Vec<T>`.
93 ///
94 /// - `Override::No` -> `other` stays untouched.
95 /// - `Override::Clear` -> `other` is set to `Vec::new()`.
96 /// - `Override::Yes { value }` -> `other` is set to `value`.
97 #[inline]
98 pub fn merge_vec(self, other: &mut Vec<T>) {
99 match self {
100 Override::No => (),
101 Override::Clear => *other = Vec::new(),
102 Override::Yes { value } => *other = value,
103 }
104 }
105}
106
107/// Package metadata based on a `pkgname` section in SRCINFO data.
108///
109/// This struct only contains package specific overrides.
110/// Only in combination with [`PackageBase`] data a full view on a package's metadata is possible.
111///
112/// All values and nested structs inside this struct, except the `name` field, are either nested
113/// [`Option`]s (e.g. `Override<Option<String>>`) or optional collections (e.g. `Option<Vec>`).
114/// This is due to the fact that all fields are overrides for the defaults set by the
115/// [`PackageBase`] struct.
116/// - If a value is `Override::No`, this indicates that the [`PackageBase`]'s value should be used.
117/// - If a value is `Override::Yes<None>`, this means that the value should be empty and the
118/// [`PackageBase`] should be ignored. The same goes for collections in the sense of
119/// `Override::Yes(Vec::new())`.
120/// - If a value is `Override::Yes(Some(value))` or `Override::Yes(vec![values])`, these values
121/// should then be used.
122///
123/// This struct merely contains the overrides that should be applied on top of the
124/// [PackageBase] to get the final definition of this package.
125//
126/// Take a look at [SourceInfoV1::packages_for_architecture] on how to get the merged representation
127/// [MergedPackage] of a package.
128#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
129pub struct Package {
130 /// The alpm-package-name of the package.
131 pub name: Name,
132 /// The (potentially overridden) description of the package.
133 pub description: Override<PackageDescription>,
134 /// The (potentially overridden) upstream URL of the package.
135 pub url: Override<Url>,
136 /// The (potentially overridden) relative path to a changelog file of the package.
137 pub changelog: Override<Changelog>,
138 /// The (potentially overridden) list of licenses that apply to the package.
139 pub licenses: Override<Vec<License>>,
140
141 // Build or package management related meta fields
142 /// The (potentially overridden) relative path to an alpm-install-scriptlet of the package.
143 pub install: Override<Install>,
144 /// The (potentially overridden) list of alpm-package-groups the package is part of.
145 pub groups: Override<Vec<String>>,
146 /// The (potentially overridden) list of build tool options used when building the package.
147 pub options: Override<Vec<MakepkgOption>>,
148 /// The (potentially overridden) list of relative paths to files in the package that should be
149 /// backed up.
150 pub backups: Override<Vec<Backup>>,
151
152 /// The architectures that are supported by this package.
153 // Despite being overridable, `architectures` field isn't of the `Override` type, as it
154 // **cannot** be cleared.
155 pub architectures: Option<Architectures>,
156 /// The map of alpm-architecture specific overrides for package relations of a package.
157 pub architecture_properties: BTreeMap<SystemArchitecture, PackageArchitecture>,
158
159 /// The (potentially overridden) list of run-time dependencies of the package.
160 pub dependencies: Override<Vec<RelationOrSoname>>,
161 /// The (potentially overridden) list of optional dependencies of the package.
162 pub optional_dependencies: Override<Vec<OptionalDependency>>,
163 /// The (potentially overridden) list of provisions of the package.
164 pub provides: Override<Vec<RelationOrSoname>>,
165 /// The (potentially overridden) list of conflicts of the package.
166 pub conflicts: Override<Vec<PackageRelation>>,
167 /// The (potentially overridden) list of replacements of the package.
168 pub replaces: Override<Vec<PackageRelation>>,
169}
170
171impl From<Name> for Package {
172 /// Creates a new [`Package`] from a [`Name`] by calling [`Package::new_with_defaults`].
173 fn from(value: Name) -> Self {
174 Package::new_with_defaults(value)
175 }
176}
177
178/// Architecture specific package properties for use in [`Package`].
179///
180/// For each [`Architecture`] defined in [`Package::architectures`] a [`PackageArchitecture`] is
181/// present in [`Package::architecture_properties`].
182#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
183pub struct PackageArchitecture {
184 /// The (potentially overridden) list of run-time dependencies of the package.
185 pub dependencies: Override<Vec<RelationOrSoname>>,
186 /// The (potentially overridden) list of optional dependencies of the package.
187 pub optional_dependencies: Override<Vec<OptionalDependency>>,
188 /// The (potentially overridden) list of provisions of the package.
189 pub provides: Override<Vec<RelationOrSoname>>,
190 /// The (potentially overridden) list of conflicts of the package.
191 pub conflicts: Override<Vec<PackageRelation>>,
192 /// The (potentially overridden) list of replacements of the package.
193 pub replaces: Override<Vec<PackageRelation>>,
194}
195
196/// Handles all potentially architecture specific, clearable entries in the [`Package::from_parsed`]
197/// function.
198///
199/// If no architecture is encountered, it simply clears the value on the [`Package`] itself.
200/// Otherwise, it's added to the respective [`PackageBase::architecture_properties`].
201macro_rules! clearable_arch_vec {
202 (
203 $architecture_properties:ident,
204 $architecture:ident,
205 $field_name:ident,
206 ) => {
207 // Check if the property is architecture specific.
208 // If so, we have to perform some checks and preparations
209 if let Some(architecture) = $architecture
210 && let Architecture::Some(system_arch) = architecture
211 {
212 let properties = $architecture_properties
213 .entry(system_arch.clone())
214 .or_default();
215 properties.$field_name = Override::Clear;
216 } else {
217 $field_name = Override::Clear;
218 }
219 };
220}
221
222/// Handles all potentially architecture specific Vector entries in the [`Package::from_parsed`]
223/// function.
224///
225/// If no architecture is encountered, it simply adds the value on the [`Package`] itself.
226/// Otherwise, it clears the value on the respective [`Package::architecture_properties`] entry.
227macro_rules! package_arch_prop {
228 (
229 $architecture_properties:ident,
230 $arch_property:ident,
231 $field_name:ident,
232 ) => {
233 // Check if the property is architecture specific.
234 // If so, we have to perform some checks and preparations
235 if let Some(architecture) = $arch_property.architecture
236 && let Architecture::Some(system_arch) = architecture
237 {
238 // Make sure the architecture specific properties are initialized.
239 let architecture_properties = $architecture_properties
240 .entry(system_arch)
241 .or_insert(PackageArchitecture::default());
242
243 // Set the architecture specific value.
244 architecture_properties
245 .$field_name
246 .get_or_insert(Vec::new())
247 .push($arch_property.value);
248 } else {
249 $field_name
250 .get_or_insert(Vec::new())
251 .push($arch_property.value)
252 }
253 };
254}
255
256impl Package {
257 /// Creates a new [`Package`] from a [`Name`].
258 ///
259 /// Uses `name` and initializes all remaining fields of [`Package`] with default values.
260 ///
261 /// # Example
262 ///
263 /// ```
264 /// use std::str::FromStr;
265 ///
266 /// use alpm_srcinfo::source_info::v1::package::Package;
267 /// use alpm_types::Name;
268 ///
269 /// # fn main() -> testresult::TestResult {
270 ///
271 /// let package = Package::new_with_defaults(Name::from_str("example_package")?);
272 /// # Ok(())
273 /// # }
274 /// ```
275 pub fn new_with_defaults(value: Name) -> Self {
276 Package {
277 name: value,
278 description: Default::default(),
279 url: Default::default(),
280 changelog: Default::default(),
281 licenses: Default::default(),
282 install: Default::default(),
283 groups: Default::default(),
284 options: Default::default(),
285 backups: Default::default(),
286 architectures: Default::default(),
287 architecture_properties: Default::default(),
288 dependencies: Default::default(),
289 optional_dependencies: Default::default(),
290 provides: Default::default(),
291 conflicts: Default::default(),
292 replaces: Default::default(),
293 }
294 }
295
296 /// Creates a new [`Package`] instance from a [`RawPackage`].
297 ///
298 /// # Parameters
299 ///
300 /// - `parsed`: The [`RawPackage`] representation of the SRCINFO data. The input guarantees that
301 /// the keyword assignments have been parsed correctly, but not yet that they represent valid
302 /// SRCINFO data as a whole.
303 pub fn from_parsed(parsed: RawPackage) -> Result<Self, Error> {
304 let mut description = Override::No;
305 let mut url = Override::No;
306 let mut licenses = Override::No;
307 let mut changelog = Override::No;
308 let mut architectures = None;
309 let mut architecture_properties: BTreeMap<SystemArchitecture, PackageArchitecture> =
310 BTreeMap::new();
311
312 // Build or package management related meta fields
313 let mut install = Override::No;
314 let mut groups = Override::No;
315 let mut options = Override::No;
316 let mut backups = Override::No;
317
318 let mut dependencies = Override::No;
319 let mut optional_dependencies = Override::No;
320 let mut provides = Override::No;
321 let mut conflicts = Override::No;
322 let mut replaces = Override::No;
323
324 // First up, check all input for potential architecture overrides.
325 for prop in parsed.properties.iter() {
326 // We're only interested in architecture properties.
327 let PackageProperty::MetaProperty(SharedMetaProperty::Architecture(architecture)) =
328 prop
329 else {
330 continue;
331 };
332 let architectures = architectures.get_or_insert(Vec::new());
333 architectures.push(architecture);
334 }
335
336 let architectures = if let Some(arch_vec) = architectures {
337 // Try to convert the list of architectures into an `Architectures` instance.
338 // This will fail if "any" is combined with any specific system architecture.
339 let architectures: Architectures = arch_vec.try_into()?;
340 Some(architectures)
341 } else {
342 None
343 };
344
345 // Next, check if there are any ClearableProperty overrides.
346 // These indicate that a value or a vector should be overridden and set to None or an empty
347 // vector, based on the property.
348 for prop in parsed.properties.iter() {
349 // We're only interested in clearable properties.
350 let PackageProperty::Clear(clearable_property) = prop else {
351 continue;
352 };
353
354 match clearable_property {
355 ClearableProperty::Description => description = Override::Clear,
356 ClearableProperty::Url => url = Override::Clear,
357 ClearableProperty::Licenses => licenses = Override::Clear,
358 ClearableProperty::Changelog => changelog = Override::Clear,
359 ClearableProperty::Install => install = Override::Clear,
360 ClearableProperty::Groups => groups = Override::Clear,
361 ClearableProperty::Options => options = Override::Clear,
362 ClearableProperty::Backups => backups = Override::Clear,
363 ClearableProperty::Dependencies(architecture) => {
364 clearable_arch_vec!(architecture_properties, architecture, dependencies,)
365 }
366 ClearableProperty::OptionalDependencies(architecture) => {
367 clearable_arch_vec!(
368 architecture_properties,
369 architecture,
370 optional_dependencies,
371 )
372 }
373 ClearableProperty::Provides(architecture) => {
374 clearable_arch_vec!(architecture_properties, architecture, provides,)
375 }
376 ClearableProperty::Conflicts(architecture) => {
377 clearable_arch_vec!(architecture_properties, architecture, conflicts,)
378 }
379 ClearableProperty::Replaces(architecture) => {
380 clearable_arch_vec!(architecture_properties, architecture, replaces,)
381 }
382 }
383 }
384
385 // Set all of the package's properties.
386 for prop in parsed.properties.into_iter() {
387 match prop {
388 // Skip empty lines and comments
389 PackageProperty::EmptyLine | PackageProperty::Comment(_) => continue,
390 PackageProperty::MetaProperty(shared_meta_property) => {
391 match shared_meta_property {
392 SharedMetaProperty::Description(inner) => {
393 description = Override::Yes { value: inner }
394 }
395 SharedMetaProperty::Url(inner) => url = Override::Yes { value: inner },
396 SharedMetaProperty::License(inner) => {
397 licenses.get_or_insert(Vec::new()).push(inner)
398 }
399 SharedMetaProperty::Changelog(inner) => {
400 changelog = Override::Yes { value: inner }
401 }
402 SharedMetaProperty::Install(inner) => {
403 install = Override::Yes { value: inner }
404 }
405 SharedMetaProperty::Group(inner) => {
406 groups.get_or_insert(Vec::new()).push(inner)
407 }
408 SharedMetaProperty::Option(inner) => {
409 options.get_or_insert(Vec::new()).push(inner)
410 }
411 SharedMetaProperty::Backup(inner) => {
412 backups.get_or_insert(Vec::new()).push(inner)
413 }
414 // We already handled these at the start of the function in a previous pass.
415 SharedMetaProperty::Architecture(_) => continue,
416 }
417 }
418 PackageProperty::RelationProperty(relation_property) => match relation_property {
419 RelationProperty::Dependency(arch_property) => {
420 package_arch_prop!(architecture_properties, arch_property, dependencies,)
421 }
422 RelationProperty::OptionalDependency(arch_property) => {
423 package_arch_prop!(
424 architecture_properties,
425 arch_property,
426 optional_dependencies,
427 )
428 }
429 RelationProperty::Provides(arch_property) => {
430 package_arch_prop!(architecture_properties, arch_property, provides,)
431 }
432 RelationProperty::Conflicts(arch_property) => {
433 package_arch_prop!(architecture_properties, arch_property, conflicts,)
434 }
435 RelationProperty::Replaces(arch_property) => {
436 package_arch_prop!(architecture_properties, arch_property, replaces,)
437 }
438 },
439 // We already handled at the start in a separate pass.
440 PackageProperty::Clear(_) => continue,
441 }
442 }
443
444 Ok(Package {
445 name: parsed.name,
446 description,
447 url,
448 changelog,
449 licenses,
450 architectures,
451 architecture_properties,
452 install,
453 groups,
454 options,
455 backups,
456 dependencies,
457 optional_dependencies,
458 provides,
459 conflicts,
460 replaces,
461 })
462 }
463}