commit:     4e9dbc12ea3b269c021bca30599b043a448acf26
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Fri Jun 30 20:54:40 2023 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Sat Jul  1 09:00:35 2023 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=4e9dbc12

OldPythonCompat: check for old PYTHON_COMPAT in modified ebuilds

Resolves: https://github.com/pkgcore/pkgcheck/issues/591
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcheck/checks/git.py | 33 +++++++++++++++++++++++++++++++--
 tests/checks/test_git.py   | 27 +++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/src/pkgcheck/checks/git.py b/src/pkgcheck/checks/git.py
index c7785729..8a80fb90 100644
--- a/src/pkgcheck/checks/git.py
+++ b/src/pkgcheck/checks/git.py
@@ -221,6 +221,20 @@ class SuspiciousSrcUriChange(results.PackageResult, 
results.Warning):
         return f"{self.filename!r} has changed SRC_URI from {self.old_uri!r} 
to {self.new_uri!r}"
 
 
+class OldPythonCompat(results.VersionResult, results.Warning):
+    """Package still lists old targets in ``PYTHON_COMPAT``."""
+
+    def __init__(self, old_targets, **kwargs):
+        super().__init__(**kwargs)
+        self.old_targets = tuple(old_targets)
+
+    @property
+    def desc(self):
+        s = pluralism(self.old_targets)
+        targets = ", ".join(self.old_targets)
+        return f"old PYTHON_COMPAT target{s} listed: [ {targets} ]"
+
+
 class _RemovalRepo(UnconfiguredTree):
     """Repository of removed packages stored in a temporary directory."""
 
@@ -278,7 +292,7 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
     _source = (sources.PackageRepoSource, (), (("source", 
GitCommitsRepoSource),))
     required_addons = (git.GitAddon,)
     known_results = frozenset(
-        [
+        {
             DirectStableKeywords,
             DirectNoMaintainer,
             RdependChange,
@@ -291,10 +305,13 @@ class GitPkgCommitsCheck(GentooRepoCheck, 
GitCommitsCheck):
             SuspiciousSrcUriChange,
             PythonPEP517WithoutRevbump,
             EAPIChangeWithoutRevbump,
-        ]
+            OldPythonCompat,
+        }
     )
 
     python_pep517_regex = re.compile("^DISTUTILS_USE_PEP517=")
+    python_compat_declare_regex = re.compile(r"^declare -a 
PYTHON_COMPAT=(?P<value>.+)$")
+    env_array_elem_regex = re.compile(r'\[\d+\]="(?P<val>.+?)"')
 
     # package categories that are committed with stable keywords
     allowed_direct_stable = frozenset(["acct-user", "acct-group"])
@@ -306,6 +323,10 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
         self.valid_arches: frozenset[str] = 
self.options.target_repo.known_arches
         self._git_addon = git_addon
         self._cleanup = []
+        self.valid_python_targets = {
+            use.removeprefix("python_targets_")
+            for use, _ in self.repo.use_expand_desc.get("python_targets", ())
+        }
 
     def cleanup(self):
         for repo in self._cleanup:
@@ -419,6 +440,14 @@ class GitPkgCommitsCheck(GentooRepoCheck, GitCommitsCheck):
             else:
                 yield MissingSlotmove(old_slot, new_slot, pkg=new_pkg)
 
+        for env_line in new_pkg.environment.data.splitlines():
+            if mo := self.python_compat_declare_regex.match(env_line):
+                if old_compat := {
+                    m.group("val")
+                    for m in re.finditer(self.env_array_elem_regex, 
mo.group("value"))
+                }.difference(self.valid_python_targets):
+                    yield OldPythonCompat(sorted(old_compat), pkg=new_pkg)
+
     def _fetchable_str(self, fetch: fetchable) -> tuple[str, str]:
         uri = tuple(fetch.uri._uri_source)[0]
         if isinstance(uri, tuple):

diff --git a/tests/checks/test_git.py b/tests/checks/test_git.py
index 03687451..ab6efee2 100644
--- a/tests/checks/test_git.py
+++ b/tests/checks/test_git.py
@@ -394,6 +394,10 @@ class TestGitPkgCommitsCheck(ReportTestCase):
         # initialize parent repo
         self.parent_git_repo = make_git_repo()
         self.parent_repo = make_repo(self.parent_git_repo.path, 
repo_id="gentoo", arches=["amd64"])
+        os.makedirs(pjoin(self.parent_git_repo.path, "profiles/desc"), 
exist_ok=True)
+        with open(pjoin(self.parent_git_repo.path, 
"profiles/desc/python_targets.desc"), "w") as f:
+            f.write("python3_10 - Build with Python 3.10\n")
+            f.write("python3_11 - Build with Python 3.11\n")
         self.parent_git_repo.add_all("initial commit")
         # create a stub pkg and commit it
         self.parent_repo.create_ebuild("cat/pkg-0", eapi="7")
@@ -751,6 +755,29 @@ class TestGitPkgCommitsCheck(ReportTestCase):
         expected = git_mod.EAPIChangeWithoutRevbump(pkg=CPV("cat/pkg-1"))
         assert r == expected
 
+    def test_old_python_compat(self):
+        # good compat
+        self.child_repo.create_ebuild("cat/pkg-0", data="PYTHON_COMPAT=( 
python3_10 python3_11 )")
+        self.child_git_repo.add_all("cat/pkg-0")
+        self.init_check()
+        self.assertNoReport(self.check, self.source)
+        # one old compat
+        self.child_repo.create_ebuild("cat/pkg-0", data="PYTHON_COMPAT=( 
python3_9 python3_10 )")
+        self.child_git_repo.add_all("cat/pkg-0")
+        self.init_check()
+        r = self.assertReport(self.check, self.source)
+        expected = git_mod.OldPythonCompat(["python3_9"], pkg=CPV("cat/pkg-0"))
+        assert r == expected
+        # two old compat
+        self.child_repo.create_ebuild(
+            "cat/pkg-0", data="PYTHON_COMPAT=( python3_9 python3_8 python3_10 
)"
+        )
+        self.child_git_repo.add_all("cat/pkg-0")
+        self.init_check()
+        r = self.assertReport(self.check, self.source)
+        expected = git_mod.OldPythonCompat(["python3_8", "python3_9"], 
pkg=CPV("cat/pkg-0"))
+        assert r == expected
+
 
 class TestGitEclassCommitsCheck(ReportTestCase):
     check_kls = git_mod.GitEclassCommitsCheck

Reply via email to