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}