1use std::{
4 collections::{BTreeMap, HashMap},
5 str::FromStr,
6};
7
8use alpm_parsers::prelude::*;
9#[cfg(doc)]
10use alpm_pkgbuild::bridge::BridgeOutput;
11use alpm_pkgbuild::bridge::{Keyword, Value};
12use alpm_types::{
13 Architectures,
14 Backup,
15 Changelog,
16 Epoch,
17 FullVersion,
18 Install,
19 License,
20 MakepkgOption,
21 Name,
22 OpenPGPIdentifier,
23 OptionalDependency,
24 PackageDescription,
25 PackageRelation,
26 PackageRelease,
27 PackageVersion,
28 RelationOrSoname,
29 SkippableChecksum,
30 Source,
31 SystemArchitecture,
32 Url,
33};
34use strum::VariantNames;
35use winnow::{
36 combinator::{alt, cut_err},
37 token::rest,
38};
39
40use crate::{
41 pkgbuild_bridge::{
42 ensure_keyword_exists,
43 ensure_no_suffix,
44 error::BridgeError,
45 parse_arch_array,
46 parse_optional_value,
47 parse_value,
48 parse_value_array,
49 },
50 source_info::{
51 parser::{ExclusivePackageBaseKeyword, RelationKeyword, SharedMetaKeyword, SourceKeyword},
52 v1::package_base::{PackageBase, PackageBaseArchitecture},
53 },
54};
55
56enum PackageBaseKeywords {
58 PkgBase,
60 PackageBase(ExclusivePackageBaseKeyword),
61 Relation(RelationKeyword),
62 SharedMeta(SharedMetaKeyword),
63 Source(SourceKeyword),
64}
65
66impl PackageBaseKeywords {
67 pub fn parser<'a>(input: &mut Input<'a>) -> PResult<'a, PackageBaseKeywords> {
75 cut_err(alt((
76 "pkgbase".map(|_| PackageBaseKeywords::PkgBase),
77 ExclusivePackageBaseKeyword::parser.map(PackageBaseKeywords::PackageBase),
78 RelationKeyword::parser.map(PackageBaseKeywords::Relation),
79 SharedMetaKeyword::parser.map(PackageBaseKeywords::SharedMeta),
80 SourceKeyword::parser.map(PackageBaseKeywords::Source),
81 )))
82 .expected_strings(
83 [
84 &["pkgbase"],
85 ExclusivePackageBaseKeyword::VARIANTS,
86 RelationKeyword::VARIANTS,
87 SharedMetaKeyword::VARIANTS,
88 SourceKeyword::VARIANTS,
89 ]
90 .into_iter()
91 .flatten(),
92 )
93 .context(StrContext::Label("package base property keyword"))
94 .parse_next(input)
95 }
96}
97
98macro_rules! package_base_value_array {
104 (
105 $keyword:ident,
106 $value:ident,
107 $field_name:ident,
108 $architecture:ident,
109 $architecture_properties:ident,
110 $parser:expr,
111 ) => {
112 if let Some(architecture) = $architecture {
113 let architecture_properties = $architecture_properties
115 .entry(architecture)
116 .or_insert(PackageBaseArchitecture::default());
117
118 architecture_properties.$field_name = parse_value_array($keyword, $value, $parser)?;
120 } else {
121 $field_name = parse_value_array($keyword, $value, $parser)?;
122 }
123 };
124}
125
126pub fn handle_package_base(
138 name: Name,
139 mut raw: HashMap<Keyword, Value>,
140) -> Result<PackageBase, BridgeError> {
141 let pkgver_keyword = Keyword::simple("pkgver");
143 let value = ensure_keyword_exists(&pkgver_keyword, &mut raw)?;
144 let package_version: PackageVersion =
145 parse_value(&pkgver_keyword, &value, PackageVersion::parser)?;
146
147 let pkgrel_keyword = Keyword::simple("pkgrel");
148 let value = ensure_keyword_exists(&pkgrel_keyword, &mut raw)?;
149 let package_release: PackageRelease =
150 parse_value(&pkgver_keyword, &value, PackageRelease::parser)?;
151
152 let mut description = None;
153 let mut url = None;
154 let mut licenses = Vec::new();
155 let mut changelog = None;
156 let mut architectures = Architectures::Some(Vec::new());
157 let mut architecture_properties = BTreeMap::new();
158
159 let mut install = None;
161 let mut groups = Vec::new();
162 let mut options = Vec::new();
163 let mut backups = Vec::new();
164
165 let mut epoch: Option<Epoch> = None;
166 let mut pgp_fingerprints = Vec::new();
167
168 let mut dependencies = Vec::new();
169 let mut optional_dependencies = Vec::new();
170 let mut provides = Vec::new();
171 let mut conflicts = Vec::new();
172 let mut replaces = Vec::new();
173 let mut check_dependencies = Vec::new();
177 let mut make_dependencies = Vec::new();
178
179 let mut sources = Vec::new();
180 let mut no_extracts = Vec::new();
181 let mut b2_checksums = Vec::new();
182 let mut md5_checksums = Vec::new();
183 let mut sha1_checksums = Vec::new();
184 let mut sha224_checksums = Vec::new();
185 let mut sha256_checksums = Vec::new();
186 let mut sha384_checksums = Vec::new();
187 let mut sha512_checksums = Vec::new();
188 let mut crc_checksums = Vec::new();
189
190 for (raw_keyword, value) in &raw {
192 let keyword = PackageBaseKeywords::parser
194 .parse(Input::new(&raw_keyword.keyword))
195 .map_err(|err| (raw_keyword.clone(), err))?;
196
197 let architecture = match &raw_keyword.suffix {
199 Some(suffix) => {
200 let arch = SystemArchitecture::parser
202 .parse(Input::new(suffix))
203 .map_err(|err| (raw_keyword.clone(), err))?;
204 Some(arch)
205 }
206 None => None,
207 };
208
209 match keyword {
211 PackageBaseKeywords::PkgBase => {
212 ensure_no_suffix(raw_keyword, architecture)?;
215 unreachable!(
216 "'pkgbase' has been handled before and should no longer exist without a suffix."
217 )
218 }
219 PackageBaseKeywords::PackageBase(keyword) => match keyword {
220 ExclusivePackageBaseKeyword::PkgVer => {
223 ensure_no_suffix(raw_keyword, architecture)?;
224 }
225 ExclusivePackageBaseKeyword::PkgRel => {
226 ensure_no_suffix(raw_keyword, architecture)?;
227 }
228 ExclusivePackageBaseKeyword::Epoch => {
229 ensure_no_suffix(raw_keyword, architecture)?;
230 epoch = parse_optional_value(raw_keyword, value, Epoch::parser_until_eof)?;
231 }
232 ExclusivePackageBaseKeyword::ValidPGPKeys => {
233 ensure_no_suffix(raw_keyword, architecture)?;
234 pgp_fingerprints = parse_value_array(
235 raw_keyword,
236 value,
237 rest.try_map(OpenPGPIdentifier::from_str),
238 )?;
239 }
240 ExclusivePackageBaseKeyword::CheckDepends => {
241 package_base_value_array!(
242 raw_keyword,
243 value,
244 check_dependencies,
245 architecture,
246 architecture_properties,
247 PackageRelation::parser_until_eof,
248 )
249 }
250 ExclusivePackageBaseKeyword::MakeDepends => package_base_value_array!(
251 raw_keyword,
252 value,
253 make_dependencies,
254 architecture,
255 architecture_properties,
256 PackageRelation::parser_until_eof,
257 ),
258 },
259 PackageBaseKeywords::SharedMeta(keyword) => match keyword {
260 SharedMetaKeyword::PkgDesc => {
261 ensure_no_suffix(raw_keyword, architecture)?;
262 description = parse_optional_value(
263 raw_keyword,
264 value,
265 rest.try_map(PackageDescription::from_str),
266 )?;
267 }
268 SharedMetaKeyword::Url => {
269 ensure_no_suffix(raw_keyword, architecture)?;
270 url = parse_optional_value(raw_keyword, value, rest.try_map(Url::from_str))?;
271 }
272 SharedMetaKeyword::License => {
273 ensure_no_suffix(raw_keyword, architecture)?;
274 licenses =
275 parse_value_array(raw_keyword, value, rest.try_map(License::from_str))?;
276 }
277 SharedMetaKeyword::Arch => {
278 ensure_no_suffix(raw_keyword, architecture)?;
279 architectures = parse_arch_array(raw_keyword, value)?;
280 }
281 SharedMetaKeyword::Changelog => {
282 ensure_no_suffix(raw_keyword, architecture)?;
283 changelog = parse_optional_value(
284 raw_keyword,
285 value,
286 rest.try_map(Changelog::from_str),
287 )?;
288 }
289 SharedMetaKeyword::Install => {
290 ensure_no_suffix(raw_keyword, architecture)?;
291 install =
292 parse_optional_value(raw_keyword, value, rest.try_map(Install::from_str))?;
293 }
294 SharedMetaKeyword::Groups => {
295 ensure_no_suffix(raw_keyword, architecture)?;
296 groups = value.clone().as_owned_vec();
297 }
298 SharedMetaKeyword::Options => {
299 ensure_no_suffix(raw_keyword, architecture)?;
300 options =
301 parse_value_array(raw_keyword, value, MakepkgOption::parser_until_eof)?;
302 }
303 SharedMetaKeyword::Backup => {
304 ensure_no_suffix(raw_keyword, architecture)?;
305 backups =
306 parse_value_array(raw_keyword, value, rest.try_map(Backup::from_str))?;
307 }
308 },
309 PackageBaseKeywords::Relation(keyword) => match keyword {
310 RelationKeyword::Depends => package_base_value_array!(
311 raw_keyword,
312 value,
313 dependencies,
314 architecture,
315 architecture_properties,
316 RelationOrSoname::parser_until_eof,
317 ),
318 RelationKeyword::OptDepends => package_base_value_array!(
319 raw_keyword,
320 value,
321 optional_dependencies,
322 architecture,
323 architecture_properties,
324 OptionalDependency::parser_until_eof,
325 ),
326 RelationKeyword::Provides => package_base_value_array!(
327 raw_keyword,
328 value,
329 provides,
330 architecture,
331 architecture_properties,
332 RelationOrSoname::parser_until_eof,
333 ),
334 RelationKeyword::Conflicts => package_base_value_array!(
335 raw_keyword,
336 value,
337 conflicts,
338 architecture,
339 architecture_properties,
340 PackageRelation::parser_until_eof,
341 ),
342 RelationKeyword::Replaces => package_base_value_array!(
343 raw_keyword,
344 value,
345 replaces,
346 architecture,
347 architecture_properties,
348 PackageRelation::parser_until_eof,
349 ),
350 },
351
352 PackageBaseKeywords::Source(keyword) => match keyword {
353 SourceKeyword::NoExtract => {
354 ensure_no_suffix(raw_keyword, architecture)?;
355 no_extracts = value.clone().as_owned_vec();
356 }
357 SourceKeyword::Source => package_base_value_array!(
358 raw_keyword,
359 value,
360 sources,
361 architecture,
362 architecture_properties,
363 rest.try_map(Source::from_str),
364 ),
365 SourceKeyword::B2sums => package_base_value_array!(
366 raw_keyword,
367 value,
368 b2_checksums,
369 architecture,
370 architecture_properties,
371 SkippableChecksum::parser_until_eof,
372 ),
373 SourceKeyword::Md5sums => package_base_value_array!(
374 raw_keyword,
375 value,
376 md5_checksums,
377 architecture,
378 architecture_properties,
379 SkippableChecksum::parser_until_eof,
380 ),
381 SourceKeyword::Sha1sums => package_base_value_array!(
382 raw_keyword,
383 value,
384 sha1_checksums,
385 architecture,
386 architecture_properties,
387 SkippableChecksum::parser_until_eof,
388 ),
389 SourceKeyword::Sha224sums => package_base_value_array!(
390 raw_keyword,
391 value,
392 sha224_checksums,
393 architecture,
394 architecture_properties,
395 SkippableChecksum::parser_until_eof,
396 ),
397 SourceKeyword::Sha256sums => package_base_value_array!(
398 raw_keyword,
399 value,
400 sha256_checksums,
401 architecture,
402 architecture_properties,
403 SkippableChecksum::parser_until_eof,
404 ),
405 SourceKeyword::Sha384sums => package_base_value_array!(
406 raw_keyword,
407 value,
408 sha384_checksums,
409 architecture,
410 architecture_properties,
411 SkippableChecksum::parser_until_eof,
412 ),
413 SourceKeyword::Sha512sums => package_base_value_array!(
414 raw_keyword,
415 value,
416 sha512_checksums,
417 architecture,
418 architecture_properties,
419 SkippableChecksum::parser_until_eof,
420 ),
421 SourceKeyword::Cksums => package_base_value_array!(
422 raw_keyword,
423 value,
424 crc_checksums,
425 architecture,
426 architecture_properties,
427 SkippableChecksum::parser_until_eof,
428 ),
429 },
430 }
431 }
432
433 let version = FullVersion::new(package_version, package_release, epoch);
434
435 Ok(PackageBase {
436 name,
437 description,
438 url,
439 changelog,
440 licenses,
441 install,
442 groups,
443 options,
444 backups,
445 version,
446 pgp_fingerprints,
447 architectures,
448 architecture_properties,
449 dependencies,
450 optional_dependencies,
451 provides,
452 conflicts,
453 replaces,
454 check_dependencies,
455 make_dependencies,
456 sources,
457 no_extracts,
458 b2_checksums,
459 md5_checksums,
460 sha1_checksums,
461 sha224_checksums,
462 sha256_checksums,
463 sha384_checksums,
464 sha512_checksums,
465 crc_checksums,
466 })
467}