1use std::collections::BTreeMap;
3
4use alpm_types::{
5 Architecture,
6 Epoch,
7 FullVersion,
8 License,
9 MakepkgOption,
10 Name,
11 OpenPGPIdentifier,
12 OptionalDependency,
13 PackageDescription,
14 PackageRelation,
15 PackageRelease,
16 PackageVersion,
17 RelationOrSoname,
18 RelativePath,
19 SkippableChecksum,
20 Source,
21 Url,
22 digests::{Blake2b512, Md5, Sha1, Sha224, Sha256, Sha384, Sha512},
23};
24use serde::{Deserialize, Serialize};
25
26use super::package::PackageArchitecture;
27use crate::{
28 Error,
29 source_info::parser::{self, PackageBaseProperty, RawPackageBase, SharedMetaProperty},
30};
31#[cfg(doc)]
32use crate::{MergedPackage, SourceInfoV1, source_info::v1::package::Package};
33
34#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
42pub struct PackageBase {
43 pub name: Name,
45 pub description: Option<PackageDescription>,
47 pub url: Option<Url>,
49 pub changelog: Option<RelativePath>,
51 pub licenses: Vec<License>,
53
54 pub install: Option<RelativePath>,
57 pub groups: Vec<String>,
59 pub options: Vec<MakepkgOption>,
61 pub backups: Vec<RelativePath>,
63
64 pub version: FullVersion,
67 pub pgp_fingerprints: Vec<OpenPGPIdentifier>,
70
71 pub architectures: Vec<Architecture>,
73 pub architecture_properties: BTreeMap<Architecture, PackageBaseArchitecture>,
75
76 pub dependencies: Vec<RelationOrSoname>,
78 pub optional_dependencies: Vec<OptionalDependency>,
80 pub provides: Vec<RelationOrSoname>,
82 pub conflicts: Vec<PackageRelation>,
84 pub replaces: Vec<PackageRelation>,
86 pub check_dependencies: Vec<PackageRelation>,
91 pub make_dependencies: Vec<PackageRelation>,
93
94 pub sources: Vec<Source>,
96 pub no_extracts: Vec<String>,
98 pub b2_checksums: Vec<SkippableChecksum<Blake2b512>>,
100 pub md5_checksums: Vec<SkippableChecksum<Md5>>,
102 pub sha1_checksums: Vec<SkippableChecksum<Sha1>>,
104 pub sha224_checksums: Vec<SkippableChecksum<Sha224>>,
106 pub sha256_checksums: Vec<SkippableChecksum<Sha256>>,
108 pub sha384_checksums: Vec<SkippableChecksum<Sha384>>,
110 pub sha512_checksums: Vec<SkippableChecksum<Sha512>>,
112}
113
114#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
119pub struct PackageBaseArchitecture {
120 pub dependencies: Vec<RelationOrSoname>,
122 pub optional_dependencies: Vec<OptionalDependency>,
124 pub provides: Vec<RelationOrSoname>,
126 pub conflicts: Vec<PackageRelation>,
128 pub replaces: Vec<PackageRelation>,
130 pub check_dependencies: Vec<PackageRelation>,
135 pub make_dependencies: Vec<PackageRelation>,
137
138 pub sources: Vec<Source>,
140 pub b2_checksums: Vec<SkippableChecksum<Blake2b512>>,
142 pub md5_checksums: Vec<SkippableChecksum<Md5>>,
144 pub sha1_checksums: Vec<SkippableChecksum<Sha1>>,
146 pub sha224_checksums: Vec<SkippableChecksum<Sha224>>,
148 pub sha256_checksums: Vec<SkippableChecksum<Sha256>>,
150 pub sha384_checksums: Vec<SkippableChecksum<Sha384>>,
152 pub sha512_checksums: Vec<SkippableChecksum<Sha512>>,
154}
155
156impl PackageBaseArchitecture {
157 pub fn merge_package_properties(&mut self, properties: PackageArchitecture) {
162 properties.dependencies.merge_vec(&mut self.dependencies);
163 properties
164 .optional_dependencies
165 .merge_vec(&mut self.optional_dependencies);
166 properties.provides.merge_vec(&mut self.provides);
167 properties.conflicts.merge_vec(&mut self.conflicts);
168 properties.replaces.merge_vec(&mut self.replaces);
169 }
170}
171
172macro_rules! package_base_arch_prop {
178 (
179 $architecture_properties:ident,
180 $arch_property:ident,
181 $field_name:ident,
182 ) => {
183 if let Some(architecture) = $arch_property.architecture {
186 let architecture_properties = $architecture_properties
188 .entry(architecture)
189 .or_insert(PackageBaseArchitecture::default());
190
191 architecture_properties
193 .$field_name
194 .push($arch_property.value);
195 } else {
196 $field_name.push($arch_property.value)
197 }
198 };
199}
200
201impl PackageBase {
202 pub fn new_with_defaults(name: Name, version: FullVersion) -> Self {
225 PackageBase {
226 name,
227 version,
228 description: None,
229 architectures: Vec::new(),
230 url: None,
231 licenses: Vec::new(),
232 groups: Vec::new(),
233 dependencies: Vec::new(),
234 make_dependencies: Vec::new(),
235 check_dependencies: Vec::new(),
236 optional_dependencies: Vec::new(),
237 provides: Vec::new(),
238 conflicts: Vec::new(),
239 replaces: Vec::new(),
240 backups: Vec::new(),
241 options: Vec::new(),
242 install: None,
243 changelog: None,
244 sources: Vec::new(),
245 no_extracts: Vec::new(),
246 md5_checksums: Vec::new(),
247 sha1_checksums: Vec::new(),
248 sha224_checksums: Vec::new(),
249 sha256_checksums: Vec::new(),
250 sha384_checksums: Vec::new(),
251 sha512_checksums: Vec::new(),
252 b2_checksums: Vec::new(),
253 pgp_fingerprints: Vec::new(),
254 architecture_properties: BTreeMap::new(),
255 }
256 }
257
258 pub fn from_parsed(parsed: RawPackageBase) -> Result<Self, Error> {
266 let mut description = None;
267 let mut url = None;
268 let mut licenses = Vec::new();
269 let mut changelog = None;
270 let mut architectures = Vec::new();
271 let mut architecture_properties = BTreeMap::new();
272
273 let mut install = None;
275 let mut groups = Vec::new();
276 let mut options = Vec::new();
277 let mut backups = Vec::new();
278
279 let mut epoch: Option<Epoch> = None;
281 let mut package_version: Option<PackageVersion> = None;
282 let mut package_release: Option<PackageRelease> = None;
283 let mut pgp_fingerprints = Vec::new();
284
285 let mut dependencies = Vec::new();
286 let mut optional_dependencies = Vec::new();
287 let mut provides = Vec::new();
288 let mut conflicts = Vec::new();
289 let mut replaces = Vec::new();
290 let mut check_dependencies = Vec::new();
294 let mut make_dependencies = Vec::new();
295
296 let mut sources = Vec::new();
297 let mut no_extracts = Vec::new();
298 let mut b2_checksums = Vec::new();
299 let mut md5_checksums = Vec::new();
300 let mut sha1_checksums = Vec::new();
301 let mut sha224_checksums = Vec::new();
302 let mut sha256_checksums = Vec::new();
303 let mut sha384_checksums = Vec::new();
304 let mut sha512_checksums = Vec::new();
305
306 for prop in parsed.properties.iter() {
308 let PackageBaseProperty::MetaProperty(SharedMetaProperty::Architecture(architecture)) =
310 prop
311 else {
312 continue;
313 };
314 architectures.push(*architecture);
315 }
316
317 if architectures.is_empty() {
320 return Err(Error::MissingKeyword { keyword: "arch" });
321 }
322
323 for prop in parsed.properties.into_iter() {
324 match prop {
325 PackageBaseProperty::EmptyLine | PackageBaseProperty::Comment(_) => continue,
327 PackageBaseProperty::PackageVersion(inner) => package_version = Some(inner),
328 PackageBaseProperty::PackageRelease(inner) => package_release = Some(inner),
329 PackageBaseProperty::PackageEpoch(inner) => epoch = Some(inner),
330 PackageBaseProperty::ValidPgpKeys(inner) => {
331 pgp_fingerprints.push(inner);
332 }
333 PackageBaseProperty::CheckDependency(arch_property) => {
334 package_base_arch_prop!(
335 architecture_properties,
336 arch_property,
337 check_dependencies,
338 )
339 }
340 PackageBaseProperty::MakeDependency(arch_property) => {
341 package_base_arch_prop!(
342 architecture_properties,
343 arch_property,
344 make_dependencies,
345 )
346 }
347 PackageBaseProperty::MetaProperty(shared_meta_property) => {
348 match shared_meta_property {
349 SharedMetaProperty::Description(inner) => description = Some(inner),
350 SharedMetaProperty::Url(inner) => url = Some(inner),
351 SharedMetaProperty::License(inner) => licenses.push(inner),
352 SharedMetaProperty::Architecture(_) => continue,
354 SharedMetaProperty::Changelog(inner) => changelog = Some(inner),
355 SharedMetaProperty::Install(inner) => install = Some(inner),
356 SharedMetaProperty::Group(inner) => groups.push(inner),
357 SharedMetaProperty::Option(inner) => options.push(inner),
358 SharedMetaProperty::Backup(inner) => backups.push(inner),
359 }
360 }
361 PackageBaseProperty::RelationProperty(relation_property) => match relation_property
362 {
363 parser::RelationProperty::Dependency(arch_property) => package_base_arch_prop!(
364 architecture_properties,
365 arch_property,
366 dependencies,
367 ),
368 parser::RelationProperty::OptionalDependency(arch_property) => {
369 package_base_arch_prop!(
370 architecture_properties,
371 arch_property,
372 optional_dependencies,
373 )
374 }
375 parser::RelationProperty::Provides(arch_property) => {
376 package_base_arch_prop!(architecture_properties, arch_property, provides,)
377 }
378 parser::RelationProperty::Conflicts(arch_property) => {
379 package_base_arch_prop!(architecture_properties, arch_property, conflicts,)
380 }
381 parser::RelationProperty::Replaces(arch_property) => {
382 package_base_arch_prop!(architecture_properties, arch_property, replaces,)
383 }
384 },
385 PackageBaseProperty::SourceProperty(source_property) => match source_property {
386 parser::SourceProperty::Source(arch_property) => {
387 package_base_arch_prop!(architecture_properties, arch_property, sources,)
388 }
389 parser::SourceProperty::NoExtract(value) => no_extracts.push(value),
390 parser::SourceProperty::B2Checksum(arch_property) => package_base_arch_prop!(
391 architecture_properties,
392 arch_property,
393 b2_checksums,
394 ),
395 parser::SourceProperty::Md5Checksum(arch_property) => {
396 package_base_arch_prop!(
397 architecture_properties,
398 arch_property,
399 md5_checksums,
400 );
401 }
402 parser::SourceProperty::Sha1Checksum(arch_property) => {
403 package_base_arch_prop!(
404 architecture_properties,
405 arch_property,
406 sha1_checksums,
407 );
408 }
409 parser::SourceProperty::Sha224Checksum(arch_property) => {
410 package_base_arch_prop!(
411 architecture_properties,
412 arch_property,
413 sha224_checksums,
414 )
415 }
416 parser::SourceProperty::Sha256Checksum(arch_property) => {
417 package_base_arch_prop!(
418 architecture_properties,
419 arch_property,
420 sha256_checksums,
421 )
422 }
423 parser::SourceProperty::Sha384Checksum(arch_property) => {
424 package_base_arch_prop!(
425 architecture_properties,
426 arch_property,
427 sha384_checksums,
428 )
429 }
430 parser::SourceProperty::Sha512Checksum(arch_property) => {
431 package_base_arch_prop!(
432 architecture_properties,
433 arch_property,
434 sha512_checksums,
435 )
436 }
437 },
438 }
439 }
440
441 let package_version = match package_version {
443 Some(package_version) => package_version,
444 None => {
445 return Err(Error::MissingKeyword { keyword: "pkgver" });
446 }
447 };
448
449 let package_release = match package_release {
451 Some(package_release) => package_release,
452 None => {
453 return Err(Error::MissingKeyword { keyword: "pkgrel" });
454 }
455 };
456 let version = FullVersion::new(package_version, package_release, epoch);
457
458 Ok(PackageBase {
459 name: parsed.name,
460 description,
461 url,
462 licenses,
463 changelog,
464 architectures,
465 architecture_properties,
466 install,
467 groups,
468 options,
469 backups,
470 version,
471 pgp_fingerprints,
472 dependencies,
473 optional_dependencies,
474 provides,
475 conflicts,
476 replaces,
477 check_dependencies,
478 make_dependencies,
479 sources,
480 no_extracts,
481 b2_checksums,
482 md5_checksums,
483 sha1_checksums,
484 sha224_checksums,
485 sha256_checksums,
486 sha384_checksums,
487 sha512_checksums,
488 })
489 }
490}