use itertools::Itertools;
use pkgcraft::pkg::ebuild::EbuildRawPkg;
use pkgcraft::restrict::Scope;
use regex::Regex;
use crate::report::ReportKind::HeaderInvalid;
use crate::scan::ScannerRun;
use crate::source::SourceKind;
use super::Context::Gentoo;
super::register! {
kind: super::CheckKind::Header,
reports: &[HeaderInvalid],
scope: Scope::Version,
sources: &[SourceKind::EbuildRawPkg],
context: &[Gentoo],
create,
}
static GENTOO_LICENSE_HEADER: &str =
"# Distributed under the terms of the GNU General Public License v2";
pub(super) fn create(_run: &ScannerRun) -> super::Runner {
Box::new(Check {
copyright_re: Regex::new(
r"^# Copyright ((?P<begin>\d{4})-)?(?P<end>\d{4}) (?P<holder>.+)$",
)
.unwrap(),
})
}
struct Check {
copyright_re: Regex,
}
impl super::CheckRun for Check {
fn run_ebuild_raw_pkg(&self, pkg: &EbuildRawPkg, run: &ScannerRun) {
let lines: Vec<_> = pkg
.data()
.lines()
.take(2)
.filter(|x| x.starts_with('#'))
.collect();
let Some((copyright, license)) = lines.into_iter().collect_tuple() else {
HeaderInvalid
.version(pkg)
.message("missing copyright and/or license")
.report(run);
return;
};
if let Some(m) = self.copyright_re.captures(copyright.trim()) {
let end: u64 = m.name("end").unwrap().as_str().parse().unwrap();
if end >= 2019 {
let holder = m.name("holder").unwrap().as_str();
if holder != "Gentoo Authors" {
HeaderInvalid
.version(pkg)
.message(format!("invalid copyright holder: {holder}"))
.location(1)
.report(run);
}
}
} else {
HeaderInvalid
.version(pkg)
.message(format!("invalid copyright: {copyright}"))
.location(1)
.report(run);
}
if license != GENTOO_LICENSE_HEADER {
HeaderInvalid
.version(pkg)
.message(format!("invalid license: {license}"))
.location(2)
.report(run);
}
}
}
#[cfg(test)]
mod tests {
use pkgcraft::test::{test_data, test_data_patched};
use crate::scan::Scanner;
use crate::test::{assert_unordered_reports, glob_reports};
use super::*;
#[test]
fn check() {
let data = test_data();
let repo = data.ebuild_repo("qa-primary").unwrap();
let scanner = Scanner::new();
let mut reports = scanner.run(repo, repo).unwrap();
assert!(!reports.any(|r| CHECK.reports.contains(&r.kind)));
let scanner = Scanner::new().reports([CHECK]);
let mut reports = scanner.run(repo, repo).unwrap();
assert!(reports.any(|r| CHECK.reports.contains(&r.kind)));
let repo = data.ebuild_repo("gentoo").unwrap();
let dir = repo.path().join(CHECK);
let expected = glob_reports!("{dir}/*/reports.json");
let reports = scanner.run(repo, repo).unwrap();
assert_unordered_reports!(reports, expected);
let data = test_data_patched();
let repo = data.ebuild_repo("gentoo").unwrap();
let reports = scanner.run(repo, repo).unwrap();
assert_unordered_reports!(reports, []);
}
}