alpm_srcinfo/source_info/v1/
merged.rs1use alpm_types::{
3    Architecture,
4    Architectures,
5    FullVersion,
6    License,
7    MakepkgOption,
8    Name,
9    OpenPGPIdentifier,
10    OptionalDependency,
11    PackageDescription,
12    PackageRelation,
13    RelationOrSoname,
14    RelativePath,
15    SkippableChecksum,
16    Source,
17    Url,
18    digests::{Blake2b512, Md5, Sha1, Sha224, Sha256, Sha384, Sha512},
19};
20use serde::{Deserialize, Serialize};
21
22#[cfg(doc)]
23use crate::source_info::v1::package::Override;
24use crate::{
25    SourceInfoV1,
26    source_info::v1::{
27        package::Package,
28        package_base::{PackageBase, PackageBaseArchitecture},
29    },
30};
31
32#[derive(Clone, Debug, Deserialize, Serialize)]
38pub struct MergedPackage {
39    pub name: Name,
41    pub description: Option<PackageDescription>,
43    pub url: Option<Url>,
45    pub licenses: Vec<License>,
47    pub architecture: Architecture,
49    pub changelog: Option<RelativePath>,
51
52    pub install: Option<RelativePath>,
55    pub groups: Vec<String>,
57    pub options: Vec<MakepkgOption>,
59    pub backups: Vec<RelativePath>,
61
62    pub version: FullVersion,
64    pub pgp_fingerprints: Vec<OpenPGPIdentifier>,
67
68    pub dependencies: Vec<RelationOrSoname>,
70    pub optional_dependencies: Vec<OptionalDependency>,
72    pub provides: Vec<RelationOrSoname>,
74    pub conflicts: Vec<PackageRelation>,
76    pub replaces: Vec<PackageRelation>,
78    pub check_dependencies: Vec<PackageRelation>,
80    pub make_dependencies: Vec<PackageRelation>,
82
83    pub sources: Vec<MergedSource>,
85    pub no_extracts: Vec<String>,
87}
88
89#[derive(Clone, Debug)]
91pub struct MergedPackagesIterator<'a> {
92    pub(crate) architecture: Architecture,
93    pub(crate) source_info: &'a SourceInfoV1,
94    pub(crate) package_iterator: std::slice::Iter<'a, Package>,
95}
96
97impl Iterator for MergedPackagesIterator<'_> {
98    type Item = MergedPackage;
99
100    fn next(&mut self) -> Option<MergedPackage> {
101        let package = self.package_iterator.find(|package| {
103            let architectures = match &package.architectures {
106                Some(value) => value,
107                None => &self.source_info.base.architectures,
108            };
109
110            match &self.architecture {
111                Architecture::Any => *architectures == Architectures::Any,
113                Architecture::Some(iterator_arch) => match architectures {
117                    Architectures::Any => true,
118                    Architectures::Some(arch_vec) => arch_vec.contains(iterator_arch),
119                },
120            }
121        })?;
122
123        Some(MergedPackage::from_base_and_package(
124            self.architecture.clone(),
125            &self.source_info.base,
126            package,
127        ))
128    }
129}
130
131#[derive(Clone, Debug, Deserialize, Serialize)]
136pub struct MergedSource {
137    pub source: Source,
139    pub b2_checksum: Option<SkippableChecksum<Blake2b512>>,
141    pub md5_checksum: Option<SkippableChecksum<Md5>>,
143    pub sha1_checksum: Option<SkippableChecksum<Sha1>>,
145    pub sha224_checksum: Option<SkippableChecksum<Sha224>>,
147    pub sha256_checksum: Option<SkippableChecksum<Sha256>>,
149    pub sha384_checksum: Option<SkippableChecksum<Sha384>>,
151    pub sha512_checksum: Option<SkippableChecksum<Sha512>>,
153}
154
155#[derive(Clone, Debug)]
161pub struct MergedSourceIterator<'a> {
162    sources: std::slice::Iter<'a, Source>,
163    b2_checksums: std::slice::Iter<'a, SkippableChecksum<Blake2b512>>,
164    md5_checksums: std::slice::Iter<'a, SkippableChecksum<Md5>>,
165    sha1_checksums: std::slice::Iter<'a, SkippableChecksum<Sha1>>,
166    sha224_checksums: std::slice::Iter<'a, SkippableChecksum<Sha224>>,
167    sha256_checksums: std::slice::Iter<'a, SkippableChecksum<Sha256>>,
168    sha384_checksums: std::slice::Iter<'a, SkippableChecksum<Sha384>>,
169    sha512_checksums: std::slice::Iter<'a, SkippableChecksum<Sha512>>,
170}
171
172impl Iterator for MergedSourceIterator<'_> {
173    type Item = MergedSource;
174
175    fn next(&mut self) -> Option<MergedSource> {
176        let source = self.sources.next()?;
177
178        Some(MergedSource {
179            source: source.clone(),
180            b2_checksum: self.b2_checksums.next().cloned(),
181            md5_checksum: self.md5_checksums.next().cloned(),
182            sha1_checksum: self.sha1_checksums.next().cloned(),
183            sha224_checksum: self.sha224_checksums.next().cloned(),
184            sha256_checksum: self.sha256_checksums.next().cloned(),
185            sha384_checksum: self.sha384_checksums.next().cloned(),
186            sha512_checksum: self.sha512_checksums.next().cloned(),
187        })
188    }
189}
190
191impl MergedPackage {
192    pub fn from_base_and_package<A: Into<Architecture>>(
209        architecture: A,
210        base: &PackageBase,
211        package: &Package,
212    ) -> MergedPackage {
213        let name = package.name.clone();
214        let architecture = &architecture.into();
215
216        let mut merged_package = Self::from_base(architecture.clone(), name, base);
218
219        merged_package.merge_package(package);
221
222        let mut architecture_properties = if let Architecture::Some(system_arch) = &architecture
226            && let Some(properties) = base.architecture_properties.get(system_arch)
227        {
228            properties.clone()
229        } else {
230            PackageBaseArchitecture::default()
231        };
232
233        if let Architecture::Some(system_arch) = architecture
235            && let Some(package_properties) = package.architecture_properties.get(system_arch)
236        {
237            architecture_properties.merge_package_properties(package_properties.clone());
238        }
239
240        merged_package.merge_architecture_properties(&architecture_properties);
242
243        merged_package
244    }
245
246    pub fn from_base<A: Into<Architecture>>(
259        architecture: A,
260        name: Name,
261        base: &PackageBase,
262    ) -> MergedPackage {
263        let merged_sources = MergedSourceIterator {
265            sources: base.sources.iter(),
266            b2_checksums: base.b2_checksums.iter(),
267            md5_checksums: base.md5_checksums.iter(),
268            sha1_checksums: base.sha1_checksums.iter(),
269            sha224_checksums: base.sha224_checksums.iter(),
270            sha256_checksums: base.sha256_checksums.iter(),
271            sha384_checksums: base.sha384_checksums.iter(),
272            sha512_checksums: base.sha512_checksums.iter(),
273        };
274
275        let architecture = match &base.architectures {
279            Architectures::Any => &Architecture::Any,
280            Architectures::Some(_) => &architecture.into(),
281        };
282
283        MergedPackage {
284            name,
285            description: base.description.clone(),
286            url: base.url.clone(),
287            licenses: base.licenses.clone(),
288            architecture: architecture.clone(),
289            changelog: base.changelog.clone(),
290            install: base.install.clone(),
291            groups: base.groups.clone(),
292            options: base.options.clone(),
293            backups: base.backups.clone(),
294            version: base.version.clone(),
295            pgp_fingerprints: base.pgp_fingerprints.clone(),
296            dependencies: base.dependencies.clone(),
297            optional_dependencies: base.optional_dependencies.clone(),
298            provides: base.provides.clone(),
299            conflicts: base.conflicts.clone(),
300            replaces: base.replaces.clone(),
301            check_dependencies: base.check_dependencies.clone(),
302            make_dependencies: base.make_dependencies.clone(),
303            sources: merged_sources.collect(),
304            no_extracts: base.no_extracts.clone(),
305        }
306    }
307
308    fn merge_package(&mut self, package: &Package) {
312        let package = package.clone();
313
314        if let Some(value) = package.architectures {
318            if matches!(value, Architectures::Any) {
319                self.architecture = Architecture::Any
320            }
321        };
322
323        package.description.merge_option(&mut self.description);
324        package.url.merge_option(&mut self.url);
325        package.changelog.merge_option(&mut self.changelog);
326        package.licenses.merge_vec(&mut self.licenses);
327        package.install.merge_option(&mut self.install);
328        package.groups.merge_vec(&mut self.groups);
329        package.options.merge_vec(&mut self.options);
330        package.backups.merge_vec(&mut self.backups);
331        package.dependencies.merge_vec(&mut self.dependencies);
332        package
333            .optional_dependencies
334            .merge_vec(&mut self.optional_dependencies);
335        package.provides.merge_vec(&mut self.provides);
336        package.conflicts.merge_vec(&mut self.conflicts);
337        package.replaces.merge_vec(&mut self.replaces);
338    }
339
340    fn merge_architecture_properties(&mut self, base_architecture: &PackageBaseArchitecture) {
346        let merged_sources = MergedSourceIterator {
348            sources: base_architecture.sources.iter(),
349            b2_checksums: base_architecture.b2_checksums.iter(),
350            md5_checksums: base_architecture.md5_checksums.iter(),
351            sha1_checksums: base_architecture.sha1_checksums.iter(),
352            sha224_checksums: base_architecture.sha224_checksums.iter(),
353            sha256_checksums: base_architecture.sha256_checksums.iter(),
354            sha384_checksums: base_architecture.sha384_checksums.iter(),
355            sha512_checksums: base_architecture.sha512_checksums.iter(),
356        };
357
358        self.dependencies
359            .extend_from_slice(&base_architecture.dependencies);
360        self.optional_dependencies
361            .extend_from_slice(&base_architecture.optional_dependencies);
362        self.provides.extend_from_slice(&base_architecture.provides);
363        self.conflicts
364            .extend_from_slice(&base_architecture.conflicts);
365        self.replaces.extend_from_slice(&base_architecture.replaces);
366        self.check_dependencies
367            .extend_from_slice(&base_architecture.check_dependencies);
368        self.make_dependencies
369            .extend_from_slice(&base_architecture.make_dependencies);
370
371        self.sources
372            .extend_from_slice(&merged_sources.collect::<Vec<MergedSource>>());
373    }
374}