alpm_lint/lint_rules/source_info/
no_architecture.rs

1//! Ensures that [SRCINFO] data contains at least one [alpm-architecture].
2//!
3//! [SRCINFO]: https://alpm.archlinux.page/specifications/SRCINFO.5.html
4//! [alpm-architecture]: https://alpm.archlinux.page/specifications/alpm-architecture.7.html
5
6use std::collections::BTreeMap;
7
8use documented::Documented;
9
10use crate::{
11    Level,
12    internal_prelude::*,
13    issue::SourceInfoIssue,
14    lint_rules::source_info::source_info_from_resource,
15};
16
17/// # What it does?
18///
19/// Ensures that an architecture (see [alpm-architecture]) is set in a [SRCINFO].
20///
21/// # Why is this bad?
22///
23/// An [alpm-architecture] must be set specifically in a [SRCINFO] as otherwise `any` would be
24/// implied.
25///
26/// # Example
27///
28/// ```ini,ignore
29/// pkgbase = test
30///     pkgver = 1.0.0
31///     pkgrel = 1
32/// ```
33///
34/// Use instead:
35///
36/// ```ini,ignore
37/// pkgbase = test
38///     pkgver = 1.0.0
39///     pkgrel = 1
40///     arch = x86_64
41/// ```
42///
43/// [SRCINFO]: https://alpm.archlinux.page/specifications/SRCINFO.5.html
44/// [alpm-architecture]: https://alpm.archlinux.page/specifications/alpm-architecture.7.html
45#[derive(Clone, Debug, Documented)]
46pub struct NoArchitecture {}
47
48impl NoArchitecture {
49    /// Create a new, boxed instance of [`NoArchitecture`].
50    pub fn new_boxed(_: &LintRuleConfiguration) -> Box<dyn LintRule> {
51        Box::new(Self {})
52    }
53}
54
55impl LintRule for NoArchitecture {
56    fn name(&self) -> &'static str {
57        "no_architecture"
58    }
59
60    fn scope(&self) -> LintScope {
61        LintScope::SourceInfo
62    }
63
64    fn level(&self) -> Level {
65        Level::Error
66    }
67
68    fn documentation(&self) -> String {
69        NoArchitecture::DOCS.into()
70    }
71
72    fn help_text(&self) -> String {
73        r#"An Architecture must be specified.
74
75Make sure to add an 'arch' field to specify the supported architectures for your package.
76"#
77        .into()
78    }
79
80    fn run(&self, resources: &Resources, issues: &mut Vec<LintIssue>) -> Result<(), Error> {
81        // Extract the SourceInfo from the given resources.
82        let source_info = source_info_from_resource(resources, self.scoped_name())?;
83
84        // Check if architectures list is empty
85        if source_info.base.architectures.is_empty() {
86            issues.push(LintIssue::from_rule(
87                self,
88                SourceInfoIssue::MissingField {
89                    field_name: "arch".to_string(),
90                }
91                .into(),
92            ));
93        }
94
95        Ok(())
96    }
97
98    fn extra_links(&self) -> Option<BTreeMap<String, String>> {
99        let mut links = BTreeMap::new();
100        links.insert(
101            "SRCINFO specification".to_string(),
102            "https://alpm.archlinux.page/specifications/SRCINFO.5.html".to_string(),
103        );
104        links.insert(
105            "alpm-architecture specification".to_string(),
106            "https://alpm.archlinux.page/specifications/alpm-architecture.7.html".to_string(),
107        );
108
109        Some(links)
110    }
111}