alpm_srcinfo/
lints.rs

1//! Linter helper functions.
2//!
3//! If you find yourself adding a new linting error and it's not just a one-off but rather used in
4//! multiple places, please add a new function in this module.
5//!
6//! All of these linter functions are designed to be used in the context of
7//! [`SourceInfoV1::from_raw`](crate::SourceInfoV1::from_raw) and the functions that're called
8//! inside it. They're passed the `errors` vector that aggregates all lints/errors during the
9//! conversion from the raw to the structured data format.
10use alpm_types::Architecture;
11
12use crate::error::{SourceInfoError, lint};
13
14/// Creates a parse error for unsafe checksums.
15///
16/// Checksums that are considered cryptographically unsafe are marked as such on the
17/// [`alpm_types::Checksum`] struct.
18pub fn unsafe_checksum(errors: &mut Vec<SourceInfoError>, line: usize, digest: &str) {
19    errors.push(lint(
20        Some(line),
21        format!(
22            "Found cryptographically unsafe checksum type \"{digest}\". Its use is discouraged!"
23        ),
24    ));
25}
26
27/// Creates a lint error for architecture specific properties when that architecture doesn't exist
28/// for a given `PackageBuild` or `Package`.
29///
30/// # Examples
31///
32/// Parsing the following SRCINFO data triggers the creation of this lint, because an assignment for
33/// `depends_aarch64` is present while no `arch = aarch64` assignment exists:
34///
35/// ```ini
36/// pkgbase = example
37///   pkgver = 0.1.0
38///   pkgrel = 1
39///   arch = x86_64
40///   depends_aarch64 = glibc
41/// pkgname = example
42/// ```
43pub fn missing_architecture_for_property(
44    errors: &mut Vec<SourceInfoError>,
45    line: usize,
46    architecture: Architecture,
47) {
48    errors.push(lint(
49        Some(line),
50        format!(
51            "Found keyword specific to \"{architecture}\", but there is no \"arch = {architecture}\" assignment"
52        ),
53    ));
54}
55
56/// Creates a lint error for when an architecture is specified multiple times.
57///
58/// # Examples
59///
60/// ```ini
61/// pkgbase = example
62///   pkgver = 0.1.0
63///   pkgrel = 1
64///   arch = x86_64
65///   arch = x86_64
66/// pkgname = example
67/// ```
68pub fn duplicate_architecture(
69    errors: &mut Vec<SourceInfoError>,
70    line: usize,
71    architecture: Architecture,
72) {
73    errors.push(lint(
74        Some(line),
75        format!("Found duplicate architecture declaration: {architecture}"),
76    ));
77}
78
79/// Creates a lint error for when a license isn't compliant with the SPDX format.
80///
81/// Take a look at [`alpm_types::License`] for more information about this format.
82pub fn non_spdx_license(errors: &mut Vec<SourceInfoError>, line: usize, license: String) {
83    errors.push(lint(
84        Some(line),
85        format!("Found license declaration that's either not in the SPDX format or not supported by SPDX: {license}"),
86    ));
87}
88
89/// Creates a lint error for a package property that is both set and unset.
90///
91/// In SRCINFO data, the overriding of a default keyword assignment in a `pkgbase` section works by
92/// assigning the keyword a new value in a `pkgname` section. Keyword overriding does not require to
93/// first unset a keyword (by assigning it an empty value).
94///
95/// # Examples
96///
97/// Parsing the following example SRCINFO data triggers the lint error, because a default set in the
98/// `pkgbase` section is first explicitly unset and then explicitly set again in a `pkgname`
99/// section. However, simply doing the latter is enough to override the keyword assignment!
100///
101/// ```ini
102/// pkgbase = example
103///   pkgver = 0.1.0
104///   pkgrel = 1
105///   depends = glibc
106///
107/// pkgname = example
108///   # this is not needed!
109///   depends =
110///   depends = gcc-libs
111/// ```
112///
113/// The following example also triggers this lint error and suggests an error in the software that
114/// created the SRCINFO data. While representing legal notation, first setting and then unsetting a
115/// keyword is no useful behavior, as both setting and unsetting of the keyword can simply be
116/// removed.
117///
118/// ```ini
119/// pkgbase = example
120///   pkgver = 0.1.0
121///   pkgrel = 1
122///   depends = glibc
123///
124/// pkgname = example
125///   depends = gcc-libs
126///   # this unsets the previous override for this package!
127///   depends =
128/// ```
129pub fn reassigned_cleared_property(errors: &mut Vec<SourceInfoError>, line: usize) {
130    errors.push(lint(
131        Some(line),
132        "This keyword is set and unset for this package. A keyword should either only be unset or overridden.",
133    ));
134}