emerge: add --complete-graph-if-new-ver < y | n >
authorZac Medico <zmedico@gentoo.org>
Wed, 21 Sep 2011 19:32:19 +0000 (12:32 -0700)
committerZac Medico <zmedico@gentoo.org>
Wed, 21 Sep 2011 19:32:19 +0000 (12:32 -0700)
Trigger the --complete-graph behavior if an installed package version will
change (upgrade or downgrade). This option is enabled by default.

man/emerge.1
pym/_emerge/create_depgraph_params.py
pym/_emerge/depgraph.py
pym/_emerge/main.py
pym/portage/tests/resolver/test_complete_graph.py [new file with mode: 0644]

index 6d9ce4c44ed68f0a60329c1cb01e14ac931974dc..4ec025127026d99abaae7142779b8ed3dd1d6da3 100644 (file)
@@ -376,6 +376,10 @@ be updated than would have otherwise been updated with the option disabled.
 Using \fB\-\-with\-bdeps=y\fR together with \fB\-\-complete\-graph\fR makes
 the graph as complete as possible.
 .TP
+.BR "\-\-complete\-graph\-if\-new\-ver < y | n >"
+Trigger the \fB\-\-complete\-graph\fR behavior if an installed package
+version will change (upgrade or downgrade). This option is enabled by default.
+.TP
 .BR \-\-config\-root=DIR
 Set the \fBPORTAGE_CONFIGROOT\fR environment variable.
 .TP
index 44dceda37d703a0dfcdd87980cd88bad41c069d2..221c440ef384a002c582387cffe93d1413b7aeac 100644 (file)
@@ -37,6 +37,12 @@ def create_depgraph_params(myopts, myaction):
        deep = myopts.get("--deep")
        if deep is not None and deep != 0:
                myparams["deep"] = deep
+
+       complete_if_new_ver = \
+               myopts.get("--complete-graph-if-new-ver")
+       if complete_if_new_ver is not None:
+               myparams["complete_if_new_ver"] = complete_if_new_ver
+
        if ("--complete-graph" in myopts or "--rebuild-if-new-rev" in myopts or
                "--rebuild-if-new-ver" in myopts or "--rebuild-if-unbuilt" in myopts):
                myparams["complete"] = True
index ffa7e167e5f5a52007b3624d09cd49b1fd9614a2..8121f68bcf5a9fc27b05e17457529e093cba0c3d 100644 (file)
@@ -4145,11 +4145,10 @@ class depgraph(object):
                        "recurse" not in self._dynamic_config.myparams:
                        return 1
 
-               if "complete" not in self._dynamic_config.myparams:
-                       # Automatically enable complete mode if there are any
-                       # downgrades, since they often break dependencies
-                       # (like in bug #353613).
-                       have_downgrade = False
+               if "complete" not in self._dynamic_config.myparams and \
+                       self._dynamic_config.myparams.get("complete_if_new_ver", "y") == "y":
+                       # Enable complete mode if an installed package version will change.
+                       version_change = False
                        for node in self._dynamic_config.digraph:
                                if not isinstance(node, Package) or \
                                        node.operation != "merge":
@@ -4157,16 +4156,15 @@ class depgraph(object):
                                vardb = self._frozen_config.roots[
                                        node.root].trees["vartree"].dbapi
                                inst_pkg = vardb.match_pkgs(node.slot_atom)
-                               if inst_pkg and inst_pkg[0] > node:
-                                       have_downgrade = True
+                               if inst_pkg and (inst_pkg[0] > node or inst_pkg[0] < node):
+                                       version_change = True
                                        break
 
-                       if have_downgrade:
+                       if version_change:
                                self._dynamic_config.myparams["complete"] = True
-                       else:
-                               # Skip complete graph mode, in order to avoid consuming
-                               # enough time to disturb users.
-                               return 1
+
+               if "complete" not in self._dynamic_config.myparams:
+                       return 1
 
                self._load_vdb()
 
index 96a6cfadb5b54198f9e310ddf1ee251a827839fc..d2fc0ac5f7a08eb46ad078ea2afcf800d8372786 100644 (file)
@@ -588,6 +588,7 @@ def parse_opts(tmpcmdline, silent=False):
        ])
 
        longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
+       y_or_n = ("y", "n")
        true_y_or_n = ("True", "y", "n")
        true_y = ("True", "y")
        argument_options = {
@@ -659,6 +660,12 @@ def parse_opts(tmpcmdline, silent=False):
                        "choices" : true_y_or_n
                },
 
+               "--complete-graph-if-new-ver": {
+                       "help"    : "trigger --complete-graph behavior if an installed package version will change (upgrade or downgrade)",
+                       "type"    : "choice",
+                       "choices" : y_or_n
+               },
+
                "--deep": {
 
                        "shortopt" : "-D",
diff --git a/pym/portage/tests/resolver/test_complete_graph.py b/pym/portage/tests/resolver/test_complete_graph.py
new file mode 100644 (file)
index 0000000..0720643
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+       ResolverPlaygroundTestCase)
+
+class CompleteGraphTestCase(TestCase):
+
+       def testCompleteGraphVersionChange(self):
+               """
+               Prevent reverse dependency breakage triggered by version changes.
+               """
+
+               ebuilds = {
+                       "sys-libs/x-0.1": {},
+                       "sys-libs/x-1": {},
+                       "sys-libs/x-2": {},
+                       "sys-apps/a-1": {"RDEPEND" : ">=sys-libs/x-1 <sys-libs/x-2"},
+               }
+
+               installed = {
+                       "sys-libs/x-1": {},
+                       "sys-apps/a-1": {"RDEPEND" : ">=sys-libs/x-1 <sys-libs/x-2"},
+               }
+
+               world = ["sys-apps/a"]
+
+               test_cases = (
+                       ResolverPlaygroundTestCase(
+                               [">=sys-libs/x-2"],
+                               options = {"--complete-graph-if-new-ver" : "n"},
+                               mergelist = ["sys-libs/x-2"],
+                               success = True,
+                       ),
+                       ResolverPlaygroundTestCase(
+                               [">=sys-libs/x-2"],
+                               options = {"--complete-graph-if-new-ver" : "y"},
+                               mergelist = ["sys-libs/x-2"],
+                               slot_collision_solutions = [],
+                               success = False,
+                       ),
+                       ResolverPlaygroundTestCase(
+                               ["<sys-libs/x-1"],
+                               options = {"--complete-graph-if-new-ver" : "n"},
+                               mergelist = ["sys-libs/x-0.1"],
+                               success = True,
+                       ),
+                       ResolverPlaygroundTestCase(
+                               ["<sys-libs/x-1"],
+                               options = {"--complete-graph-if-new-ver" : "y"},
+                               mergelist = ["sys-libs/x-0.1"],
+                               slot_collision_solutions = [],
+                               success = False,
+                       ),
+               )
+
+               playground = ResolverPlayground(ebuilds=ebuilds,
+                       installed=installed, world=world, debug=False)
+
+               try:
+                       for test_case in test_cases:
+                               playground.run_TestCase(test_case)
+                               self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+               finally:
+                       playground.cleanup()