>From a63e7044b93d56cc3d029912e7befcb657726fb1 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Thu, 6 Nov 2025 21:28:36 +0100
Subject: [PATCH 7/7] Add deb822.PkgRelation.{holds_on_arch,
 holds_with_profiles}

The next concern after parse_relations is probably to check that the
relation holds in a given context.  Enable callers to do that without
depending on the internal representation of arch and profiles
restrictions.
---
 src/debian/deb822.py | 27 +++++++++++++++++++++++++++
 tests/test_deb822.py | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/src/debian/deb822.py b/src/debian/deb822.py
index 4929583..b230e30 100644
--- a/src/debian/deb822.py
+++ b/src/debian/deb822.py
@@ -1487,6 +1487,33 @@ class PkgRelation:
         cnf = map(cls.__pipe_sep_RE.split, tl_deps)
         return [[parse_rel(or_dep) for or_dep in or_deps] for or_deps in cnf]
 
+    @staticmethod
+    def holds_on_arch(relation: ParsedRelation, arch: str) -> bool:
+        """Is relation active on the given architecture?
+
+        Check arch against a disjunction like [amd64 armel]
+        or a conjonction of exclusions like [!amd64 !armel].
+
+        Per policy, the list is non empty and ! affects all names or none."""
+        archs = relation["arch"]
+        return (archs is None
+                or archs[0].enabled == any(arch == a.arch for a in archs))
+
+    @staticmethod
+    def holds_with_profiles(
+        relation: ParsedRelation,
+        profiles: collections.abc.Container[str],
+    ) -> bool:
+        """Is relation active under the given profiles?
+
+        In the relation, '<a !b> <c>' requires that profiles
+        either contains a but not b, or contains c."""
+        restrictions = relation["restrictions"]
+        return (restrictions is None
+                or any(all(term.enabled == (term.profile in profiles)
+                           for term in restriction_list)
+                       for restriction_list in restrictions))
+
     @staticmethod
     def str(rels: List[List[PkgRelation.ParsedRelation]]) -> builtins.str:
         """Format to string structured inter-package relationships
diff --git a/tests/test_deb822.py b/tests/test_deb822.py
index 97623dd..a632e4f 100755
--- a/tests/test_deb822.py
+++ b/tests/test_deb822.py
@@ -1701,6 +1701,46 @@ class TestPkgRelations:
         assert term == "native"
         assert deb822.PkgRelation.str(rel) == r
 
+    def test_holds_on_arch(self) -> None:
+        A = "a"                 # the current architecture
+        for one_relation, expected in (
+            # no restriction
+            ("foo",                     True),
+            # architecture membership
+            ("foo [ a1  a   a2]",       True),
+            ("foo [ a1      a2]",       False),
+            # architecture exclusions
+            ("foo [!a1    !a2]",        True),
+            ("foo [!a1 !a !a2]",        False),
+        ):
+            rel = deb822.PkgRelation.parse_relations(one_relation)[0][0]
+            got = deb822.PkgRelation.holds_on_arch(rel, A)
+            assert got == expected, one_relation
+
+    def test_holds_with_profiles(self) -> None:
+        P = ("p1", "p2")        # the current profiles
+        for one_relation, expected in (
+            # no restriction
+            ("foo",                     True),
+            # profile membership
+            ("foo <p1>",                True),
+            ("foo <p>",                 False),
+            # profile negation
+            ("foo <!p1>",               False),
+            ("foo <!p>",                True),
+            # profile conjunction
+            ("foo <p p1>",              False),
+            ("foo <p1 p2>",             True),
+            ("foo <p1 p2 p>",           False),
+            # profile disjunction
+            ("foo <p> <p1>",            True),
+            ("foo <p> <q>",             False),
+            ("foo <p1> <p2>",           True),
+        ):
+            rel = deb822.PkgRelation.parse_relations(one_relation)[0][0]
+            got = deb822.PkgRelation.holds_with_profiles(rel, P)
+            assert got == expected, one_relation
+
 
 class TestVersionAccessor:
 
-- 
2.47.3

