commit: afc779b8a445cf95f1ea907bb1ac651cf9440815 Author: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> AuthorDate: Wed Jun 21 18:20:57 2023 +0000 Commit: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> CommitDate: Sat Jun 24 05:49:32 2023 +0000 URL: https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=afc779b8
ProfilesCheck: for unknown packages, mention last match removed https://github.com/pkgcore/pkgcheck/issues/588 Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org> src/pkgcheck/checks/profiles.py | 48 +++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/pkgcheck/checks/profiles.py b/src/pkgcheck/checks/profiles.py index 3420e471..b9108f83 100644 --- a/src/pkgcheck/checks/profiles.py +++ b/src/pkgcheck/checks/profiles.py @@ -1,5 +1,6 @@ """Various profile-related checks.""" +from datetime import datetime import os from collections import defaultdict from typing import Iterable @@ -16,6 +17,21 @@ from .. import addons, base, results, sources from . import Check, RepoCheck +class OutdatedProfilePackage(results.ProfilesResult, results.Warning): + """Profile files includes package entry that doesn't exist in the repo + for a mentioned period of time.""" + + def __init__(self, path, atom, age): + super().__init__() + self.path = path + self.atom = str(atom) + self.age = float(age) + + @property + def desc(self): + return f"{self.path!r}: outdated package entry: {self.atom!r}, last match removed {self.age} years ago" + + class UnknownProfilePackage(results.ProfilesResult, results.Warning): """Profile files includes package entry that doesn't exist in the repo.""" @@ -190,9 +206,10 @@ class ProfilesCheck(Check): """Scan repo profiles for unknown flags/packages.""" _source = sources.ProfilesRepoSource - required_addons = (addons.UseAddon, addons.KeywordsAddon) + required_addons = (addons.UseAddon, addons.KeywordsAddon, addons.git.GitAddon) known_results = frozenset( { + OutdatedProfilePackage, UnknownProfilePackage, UnmatchedProfilePackageUnmask, UnknownProfilePackageUse, @@ -210,12 +227,20 @@ class ProfilesCheck(Check): # mapping between known files and verification methods known_files = {} - def __init__(self, *args, use_addon: addons.UseAddon, keywords_addon: addons.KeywordsAddon): + def __init__( + self, + *args, + use_addon: addons.UseAddon, + keywords_addon: addons.KeywordsAddon, + git_addon: addons.git.GitAddon, + ): super().__init__(*args) repo = self.options.target_repo self.keywords = keywords_addon self.search_repo = self.options.search_repo self.profiles_dir = repo.config.profiles_base + self.today = datetime.today() + self.existence_repo = git_addon.cached_repo(addons.git.GitRemovedRepo) self.use_expand_groups = { use.upper(): frozenset({val.removeprefix(f"{use}_") for val, _desc in vals}) for use, vals in repo.config.use_expand_desc.items() @@ -229,6 +254,17 @@ class ProfilesCheck(Check): | use_addon.global_iuse_implicit ) + def _report_unknown_atom(self, path, atom): + if not isinstance(atom, atom_cls): + atom = atom_cls(atom) + if matches := self.existence_repo.match(atom): + removal = max(x.time for x in matches) + removal = datetime.fromtimestamp(removal) + years = (self.today - removal).days / 365.2425 + return OutdatedProfilePackage(path, atom, round(years, 2)) + else: + return UnknownProfilePackage(path, atom) + @verify_files(("parent", "parents"), ("eapi", "eapi")) def _pull_attr(self, *args): """Verification only needs to pull the profile attr.""" @@ -279,7 +315,7 @@ class ProfilesCheck(Check): def _pkg_atoms(self, filename, node, vals): for x in iflatten_instance(vals, atom_cls): if not isinstance(x, bool) and not self.search_repo.match(x): - yield UnknownProfilePackage(pjoin(node.name, filename), x) + yield self._report_unknown_atom(pjoin(node.name, filename), x) @verify_files( ("package.mask", "masks"), @@ -292,10 +328,10 @@ class ProfilesCheck(Check): unmasked, masked = vals for x in masked: if not self.search_repo.match(x): - yield UnknownProfilePackage(pjoin(node.name, filename), x) + yield self._report_unknown_atom(pjoin(node.name, filename), x) for x in unmasked: if not self.search_repo.match(x): - yield UnknownProfilePackage(pjoin(node.name, filename), x) + yield self._report_unknown_atom(pjoin(node.name, filename), x) elif x not in all_masked: yield UnmatchedProfilePackageUnmask(pjoin(node.name, filename), x) @@ -324,7 +360,7 @@ class ProfilesCheck(Check): pjoin(node.name, filename), a, unknown_enabled ) else: - yield UnknownProfilePackage(pjoin(node.name, filename), a) + yield self._report_unknown_atom(pjoin(node.name, filename), a) @verify_files(("make.defaults", "make_defaults")) def _make_defaults(self, filename: str, node: sources.ProfileNode, vals: dict[str, str]):