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