commit:     92c15c0f33a24fbf1bd673bc3dc5526e021e5c47
Author:     Jannik Glückert <jannik.glueckert <AT> gmail <DOT> com>
AuthorDate: Sat Jun 14 19:40:57 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Mon Oct 20 17:31:52 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=92c15c0f

portage.dep.Atom: improve slot regex

We would previously allow slots without a main slot name, such as
":/subslot". This has never been allowed in PMS.

Signed-off-by: Jannik Glückert <jannik.glueckert <AT> gmail.com>
Part-of: https://github.com/gentoo/portage/pull/1445
Closes: https://github.com/gentoo/portage/pull/1445
Signed-off-by: Sam James <sam <AT> gentoo.org>

 lib/portage/dep/__init__.py        | 31 +++++++++++++++----------------
 lib/portage/tests/dep/test_atom.py |  1 +
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/lib/portage/dep/__init__.py b/lib/portage/dep/__init__.py
index ecd1b522cf..31d0900f90 100644
--- a/lib/portage/dep/__init__.py
+++ b/lib/portage/dep/__init__.py
@@ -90,11 +90,18 @@ def _get_slot_dep_re(eapi_attrs: portage.eapi._eapi_attrs) 
-> re.Pattern:
         return slot_re
 
     if eapi_attrs.slot_operator:
-        slot_re = _slot + r"?(\*|=|/" + _slot + r"=?)?"
+        slot_re = (
+            "("
+            # we don't want to name this group "slot",
+            # as that group name is already used in _get_atom_re()
+            + f"(?P<main_slot>{_slot})"
+            + ("(/" + f"(?P<sub_slot>{_slot})" + ")?")
+            + ")?"
+        ) + "(?P<slot_operator>[*=])?"
     else:
         slot_re = _slot
 
-    slot_re = re.compile("^" + slot_re + "$", re.VERBOSE | re.ASCII)
+    slot_re = re.compile(rf"^{slot_re}\Z", re.VERBOSE | re.ASCII)
 
     _slot_dep_re_cache[cache_key] = slot_re
     return slot_re
@@ -1628,22 +1635,14 @@ class Atom(str):
             if slot_match is None:
                 raise InvalidAtom(self)
             if eapi_attrs.slot_operator:
-                self.__dict__["slot"] = slot_match.group(1)
-                sub_slot = slot_match.group(2)
-                if sub_slot is not None:
-                    sub_slot = sub_slot.lstrip("/")
-                if sub_slot in ("*", "="):
-                    self.__dict__["sub_slot"] = None
-                    self.__dict__["slot_operator"] = sub_slot
-                else:
-                    slot_operator = None
-                    if sub_slot is not None and sub_slot[-1:] == "=":
-                        slot_operator = sub_slot[-1:]
-                        sub_slot = sub_slot[:-1]
-                    self.__dict__["sub_slot"] = sub_slot
-                    self.__dict__["slot_operator"] = slot_operator
+                self.__dict__["slot"] = slot_match.group("main_slot")
+                self.__dict__["sub_slot"] = slot_match.group("sub_slot")
+                self.__dict__["slot_operator"] = 
slot_match.group("slot_operator")
                 if self.slot is not None and self.slot_operator == "*":
                     raise InvalidAtom(self)
+                # since both parts are optional, we could theoretically match 
on nothing
+                if self.slot is None and self.slot_operator is None:
+                    raise InvalidAtom(self)
             else:
                 self.__dict__["slot"] = slot
                 self.__dict__["sub_slot"] = None

diff --git a/lib/portage/tests/dep/test_atom.py 
b/lib/portage/tests/dep/test_atom.py
index 2b29f20ccb..09b4e1c649 100644
--- a/lib/portage/tests/dep/test_atom.py
+++ b/lib/portage/tests/dep/test_atom.py
@@ -154,6 +154,7 @@ class TestAtom(TestCase):
             (Atom("sys-apps/portage"), False, False),
             ("cat/pkg\n", False, False),
             ("cat/Ҙ", False, False),
+            ("cat/pkg:/slot", False, False),
             ("+cat/pkg", False, False),
             ("-cat/pkg", False, False),
             (".cat/pkg", False, False),

Reply via email to