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}