public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Zac Medico" <zmedico@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/portage:master commit in: lib/_emerge/, lib/portage/tests/resolver/
Date: Wed,  6 Dec 2023 20:29:49 +0000 (UTC)	[thread overview]
Message-ID: <1701894194.1d856747ada48f8d32c033091b1156cc655efed3.zmedico@gentoo> (raw)

commit:     1d856747ada48f8d32c033091b1156cc655efed3
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Dec  6 06:05:46 2023 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Dec  6 20:23:14 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=1d856747

DepPriority{Normal,Satisfied}Range: weaken _ignore_runtime for cross root

When the dependency parent is for a cross root (ROOT != /) package,
weaken _ignore_runtime in order to tolerate runtime cycles that are
less problematic for cross root packages.

The included test case fails with this error without the fix:

 * Error: circular dependencies:

(dev-libs/gmp-6.3.0:0/10.4::test_repo, binary scheduled for merge to '/tmp/tmp25nwdjn7/cross_root/') depends on
 (sys-devel/gcc-13.2.1_p20230826:0/0::test_repo, binary scheduled for merge to '/tmp/tmp25nwdjn7/cross_root/') (runtime)
  (dev-libs/gmp-6.3.0:0/10.4::test_repo, binary scheduled for merge to '/tmp/tmp25nwdjn7/cross_root/') (runtime_slot_op)

It might be possible to break this cycle
by applying the following change:
- dev-libs/gmp-6.3.0 (Change USE: -cxx)

Bug: https://bugs.gentoo.org/919174
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/DepPriority.py                         |   4 +-
 lib/_emerge/DepPriorityNormalRange.py              |   4 +-
 lib/_emerge/DepPrioritySatisfiedRange.py           |   1 +
 lib/_emerge/UnmergeDepPriority.py                  |   3 +-
 lib/_emerge/depgraph.py                            |  46 ++++--
 lib/portage/tests/resolver/meson.build             |   1 +
 .../tests/resolver/test_cross_dep_priority.py      | 164 +++++++++++++++++++++
 7 files changed, 208 insertions(+), 15 deletions(-)

diff --git a/lib/_emerge/DepPriority.py b/lib/_emerge/DepPriority.py
index 99d38477e2..8d282b937a 100644
--- a/lib/_emerge/DepPriority.py
+++ b/lib/_emerge/DepPriority.py
@@ -1,11 +1,11 @@
-# Copyright 1999-2013 Gentoo Foundation
+# Copyright 1999-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.AbstractDepPriority import AbstractDepPriority
 
 
 class DepPriority(AbstractDepPriority):
-    __slots__ = ("satisfied", "optional", "ignored")
+    __slots__ = ("cross", "ignored", "optional", "satisfied")
 
     def __int__(self):
         """

diff --git a/lib/_emerge/DepPriorityNormalRange.py b/lib/_emerge/DepPriorityNormalRange.py
index d7e4381b47..cb0e6c26b1 100644
--- a/lib/_emerge/DepPriorityNormalRange.py
+++ b/lib/_emerge/DepPriorityNormalRange.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.DepPriority import DepPriority
@@ -41,7 +41,7 @@ class DepPriorityNormalRange:
         # to adjust this appropriately. But only build time dependencies
         # are optional right now, so it's not an issue as-is.
         return bool(
-            not priority.runtime_slot_op
+            not (priority.runtime_slot_op and not priority.cross)
             and (priority.optional or not priority.buildtime)
         )
 

diff --git a/lib/_emerge/DepPrioritySatisfiedRange.py b/lib/_emerge/DepPrioritySatisfiedRange.py
index 0d42e7613d..b3bc90c2ff 100644
--- a/lib/_emerge/DepPrioritySatisfiedRange.py
+++ b/lib/_emerge/DepPrioritySatisfiedRange.py
@@ -96,6 +96,7 @@ class DepPrioritySatisfiedRange:
             (
                 (not priority.runtime_slot_op)
                 or (priority.satisfied and priority.runtime_slot_op)
+                or priority.cross
             )
             and (priority.satisfied or priority.optional or not priority.buildtime)
         )

diff --git a/lib/_emerge/UnmergeDepPriority.py b/lib/_emerge/UnmergeDepPriority.py
index ff81eff46f..d818bad1b8 100644
--- a/lib/_emerge/UnmergeDepPriority.py
+++ b/lib/_emerge/UnmergeDepPriority.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2013 Gentoo Foundation
+# Copyright 1999-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from _emerge.AbstractDepPriority import AbstractDepPriority
@@ -6,6 +6,7 @@ from _emerge.AbstractDepPriority import AbstractDepPriority
 
 class UnmergeDepPriority(AbstractDepPriority):
     __slots__ = (
+        "cross",
         "ignored",
         "optional",
         "satisfied",

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index 9b09701021..59c78c7354 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -3630,7 +3630,7 @@ class depgraph:
                     blocker=False,
                     depth=depth,
                     parent=pkg,
-                    priority=self._priority(runtime=True),
+                    priority=self._priority(cross=self._cross(pkg.root), runtime=True),
                     root=pkg.root,
                 )
                 if not self._add_dep(dep, allow_unsatisfied=allow_unsatisfied):
@@ -3968,17 +3968,26 @@ class depgraph:
         # _dep_disjunctive_stack first, so that choices for build-time
         # deps influence choices for run-time deps (bug 639346).
         deps = (
-            (myroot, edepend["RDEPEND"], self._priority(runtime=True)),
+            (
+                myroot,
+                edepend["RDEPEND"],
+                self._priority(cross=self._cross(pkg.root), runtime=True),
+            ),
             (
                 self._frozen_config._running_root.root,
                 edepend["IDEPEND"],
-                self._priority(runtime=True),
+                self._priority(cross=self._cross(pkg.root), runtime=True),
+            ),
+            (
+                myroot,
+                edepend["PDEPEND"],
+                self._priority(cross=self._cross(pkg.root), runtime_post=True),
             ),
-            (myroot, edepend["PDEPEND"], self._priority(runtime_post=True)),
             (
                 depend_root,
                 edepend["DEPEND"],
                 self._priority(
+                    cross=self._cross(pkg.root),
                     buildtime=True,
                     optional=(pkg.built or ignore_depend_deps),
                     ignored=ignore_depend_deps,
@@ -3988,6 +3997,7 @@ class depgraph:
                 self._frozen_config._running_root.root,
                 edepend["BDEPEND"],
                 self._priority(
+                    cross=self._cross(pkg.root),
                     buildtime=True,
                     optional=(pkg.built or ignore_bdepend_deps),
                     ignored=ignore_bdepend_deps,
@@ -4036,7 +4046,9 @@ class depgraph:
                             self._queue_disjunctive_deps(
                                 pkg,
                                 dep_root,
-                                self._priority(runtime_post=True),
+                                self._priority(
+                                    cross=self._cross(pkg.root), runtime_post=True
+                                ),
                                 test_deps,
                             )
                         )
@@ -4044,7 +4056,9 @@ class depgraph:
                         if test_deps and not self._add_pkg_dep_string(
                             pkg,
                             dep_root,
-                            self._priority(runtime_post=True),
+                            self._priority(
+                                cross=self._cross(pkg.root), runtime_post=True
+                            ),
                             test_deps,
                             allow_unsatisfied,
                         ):
@@ -4359,7 +4373,10 @@ class depgraph:
                     return 0
 
             for atom, child in self._minimize_children(
-                pkg, self._priority(runtime=True), root_config, atoms
+                pkg,
+                self._priority(cross=self._cross(pkg.root), runtime=True),
+                root_config,
+                atoms,
             ):
                 # If this was a specially generated virtual atom
                 # from dep_check, map it back to the original, in
@@ -4369,7 +4386,7 @@ class depgraph:
                 atom = getattr(atom, "_orig_atom", atom)
 
                 # This is a GLEP 37 virtual, so its deps are all runtime.
-                mypriority = self._priority(runtime=True)
+                mypriority = self._priority(cross=self._cross(pkg.root), runtime=True)
                 if not atom.blocker:
                     inst_pkgs = [
                         inst_pkg
@@ -4616,6 +4633,13 @@ class depgraph:
             priority_constructor = DepPriority
         return priority_constructor(**kwargs)
 
+    def _cross(self, eroot):
+        """
+        Returns True if the ROOT for the given EROOT is not /,
+        or EROOT is cross-prefix.
+        """
+        return eroot != self._frozen_config._running_root.root
+
     def _dep_expand(self, root_config, atom_without_category):
         """
         @param root_config: a root config instance
@@ -5788,7 +5812,9 @@ class depgraph:
                             node_priority = priority.copy()
                     else:
                         # virtuals only have runtime deps
-                        node_priority = self._priority(runtime=True)
+                        node_priority = self._priority(
+                            cross=self._cross(node_parent.root), runtime=True
+                        )
 
                     k = Dependency(
                         atom=parent_atom,
@@ -5874,7 +5900,7 @@ class depgraph:
                 pkg._metadata.get("RDEPEND", ""),
                 myuse=self._pkg_use_enabled(pkg),
                 parent=pkg,
-                priority=self._priority(runtime=True),
+                priority=self._priority(cross=self._cross(pkg.root), runtime=True),
             )
         except InvalidDependString as e:
             if not pkg.installed:

diff --git a/lib/portage/tests/resolver/meson.build b/lib/portage/tests/resolver/meson.build
index 770027ac47..77c65a511e 100644
--- a/lib/portage/tests/resolver/meson.build
+++ b/lib/portage/tests/resolver/meson.build
@@ -21,6 +21,7 @@ py.install_sources(
         'test_circular_dependencies.py',
         'test_complete_graph.py',
         'test_complete_if_new_subslot_without_revbump.py',
+        'test_cross_dep_priority.py',
         'test_depclean.py',
         'test_depclean_order.py',
         'test_depclean_slot_unavailable.py',

diff --git a/lib/portage/tests/resolver/test_cross_dep_priority.py b/lib/portage/tests/resolver/test_cross_dep_priority.py
new file mode 100644
index 0000000000..10f2eb36e2
--- /dev/null
+++ b/lib/portage/tests/resolver/test_cross_dep_priority.py
@@ -0,0 +1,164 @@
+# Copyright 2023 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import subprocess
+import os
+
+import portage
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (
+    ResolverPlayground,
+    ResolverPlaygroundTestCase,
+)
+
+
+class CrossDepPriorityTestCase(TestCase):
+    def testCrossDepPriority(self):
+        """
+        Test bug 919174, where cross-root merge to an empty root
+        failed due to circular dependencies.
+        """
+        ebuilds = {
+            "dev-lang/python-3.11.6": {
+                "EAPI": "8",
+                "DEPEND": "sys-apps/util-linux:=",
+                "RDEPEND": "sys-apps/util-linux:=",
+            },
+            "sys-apps/util-linux-2.38.1-r2": {
+                "EAPI": "8",
+                "DEPEND": "selinux? ( >=sys-libs/libselinux-2.2.2-r4 )",
+                "RDEPEND": "selinux? ( >=sys-libs/libselinux-2.2.2-r4 )",
+                "IUSE": "selinux",
+            },
+            "sys-libs/libselinux-3.5-r1": {
+                "EAPI": "8",
+                "DEPEND": "python? ( dev-lang/python )",
+                "RDEPEND": "python? ( dev-lang/python )",
+                "IUSE": "python",
+            },
+            "dev-libs/gmp-6.3.0": {
+                "EAPI": "8",
+                "SLOT": "0/10.4",
+                "DEPEND": "cxx? ( sys-devel/gcc )",
+                "RDEPEND": "cxx? ( sys-devel/gcc )",
+                "IUSE": "cxx",
+            },
+            "sys-devel/gcc-13.2.1_p20230826": {
+                "EAPI": "8",
+                "DEPEND": ">=dev-libs/gmp-4.3.2:0=",
+                "RDEPEND": ">=dev-libs/gmp-4.3.2:0=",
+            },
+        }
+
+        installed = {
+            "dev-lang/python-3.11.6": {
+                "EAPI": "8",
+                "KEYWORDS": "x86",
+                "DEPEND": "sys-apps/util-linux:0/0=",
+                "RDEPEND": "sys-apps/util-linux:0/0=",
+            },
+            "sys-apps/util-linux-2.38.1-r2": {
+                "EAPI": "8",
+                "KEYWORDS": "x86",
+                "DEPEND": "selinux? ( >=sys-libs/libselinux-2.2.2-r4 )",
+                "RDEPEND": "selinux? ( >=sys-libs/libselinux-2.2.2-r4 )",
+                "IUSE": "selinux",
+                "USE": "selinux",
+            },
+            "sys-libs/libselinux-3.5-r1": {
+                "EAPI": "8",
+                "KEYWORDS": "x86",
+                "DEPEND": "python? ( dev-lang/python )",
+                "RDEPEND": "python? ( dev-lang/python )",
+                "IUSE": "python",
+                "USE": "python",
+            },
+            "dev-libs/gmp-6.3.0": {
+                "EAPI": "8",
+                "KEYWORDS": "x86",
+                "SLOT": "0/10.4",
+                "DEPEND": "cxx? ( sys-devel/gcc )",
+                "RDEPEND": "cxx? ( sys-devel/gcc )",
+                "IUSE": "cxx",
+                "USE": "cxx",
+            },
+            "sys-devel/gcc-13.2.1_p20230826": {
+                "EAPI": "8",
+                "KEYWORDS": "x86",
+                "DEPEND": ">=dev-libs/gmp-4.3.2:0/10.4=",
+                "RDEPEND": ">=dev-libs/gmp-4.3.2:0/10.4=",
+            },
+        }
+
+        world = [
+            "sys-apps/util-linux",
+            "sys-devel/gcc",
+        ]
+
+        user_config = {
+            "make.conf": ('USE="cxx python selinux"',),
+        }
+
+        test_cases = (
+            ResolverPlaygroundTestCase(
+                ["@world"],
+                options={"--emptytree": True},
+                success=True,
+                mergelist=[
+                    "dev-libs/gmp-6.3.0",
+                    "sys-devel/gcc-13.2.1_p20230826",
+                    "sys-apps/util-linux-2.38.1-r2",
+                    "dev-lang/python-3.11.6",
+                    "sys-libs/libselinux-3.5-r1",
+                ],
+            ),
+        )
+
+        playground = ResolverPlayground(
+            ebuilds=ebuilds,
+            installed=installed,
+            world=world,
+            user_config=user_config,
+        )
+        try:
+            for test_case in test_cases:
+                playground.run_TestCase(test_case)
+                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+
+            # Since ResolverPlayground does not internally support
+            # cross-root, test with emerge.
+            cross_root = os.path.join(playground.settings["EPREFIX"], "cross_root")
+            world_file = os.path.join(
+                cross_root,
+                playground.settings["EPREFIX"].lstrip(os.sep),
+                portage.const.WORLD_FILE,
+            )
+            os.makedirs(os.path.dirname(world_file))
+            shutil.copy(
+                os.path.join(playground.settings["EPREFIX"], portage.const.WORLD_FILE),
+                world_file,
+            )
+            result = subprocess.run(
+                [
+                    "emerge",
+                    f"--root={cross_root}",
+                    "--pretend",
+                    "--verbose",
+                    "--usepkgonly",
+                    "--quickpkg-direct=y",
+                    "@world",
+                ],
+                env=playground.settings.environ(),
+                stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT,
+            )
+            output = result.stdout.decode(errors="replace")
+            try:
+                self.assertTrue("5 packages (5 new, 5 binaries)" in output)
+                self.assertEqual(result.returncode, os.EX_OK)
+            except Exception:
+                print(output)
+                raise
+        finally:
+            playground.cleanup()


             reply	other threads:[~2023-12-06 20:29 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-06 20:29 Zac Medico [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-05-26 18:48 [gentoo-commits] proj/portage:master commit in: lib/_emerge/, lib/portage/tests/resolver/ Zac Medico
2023-12-24 19:30 Zac Medico
2023-11-28 22:42 Zac Medico
2023-11-28 22:26 Sam James
2023-11-28  4:20 Zac Medico
2023-11-19 17:56 Zac Medico
2023-06-16  3:34 Sam James
2023-06-16  3:34 Sam James
2020-11-22  6:13 Zac Medico
2020-09-21  5:39 Zac Medico
2020-02-15  0:05 Zac Medico
2019-09-12  1:51 Zac Medico

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1701894194.1d856747ada48f8d32c033091b1156cc655efed3.zmedico@gentoo \
    --to=zmedico@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox