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