--autounmask: If we can't do a change because of REQUIRED_USE, give at least a good...
authorSebastian Luther <SebastianLuther@gmx.de>
Fri, 20 Aug 2010 10:54:05 +0000 (12:54 +0200)
committerZac Medico <zmedico@gentoo.org>
Fri, 20 Aug 2010 12:15:55 +0000 (05:15 -0700)
pym/_emerge/depgraph.py
pym/portage/dep/__init__.py
pym/portage/tests/resolver/test_autounmask.py

index 7f705513b118ac25fe4cb957111cb9b187ddf5d3..cb030d7c3f111c5f313babe7f82e56519770b40d 100644 (file)
@@ -16,7 +16,7 @@ from portage import digraph
 from portage.const import PORTAGE_PACKAGE_ATOM
 from portage.dbapi import dbapi
 from portage.dbapi.dep_expand import dep_expand
-from portage.dep import Atom, extract_affecting_use, check_required_use
+from portage.dep import Atom, extract_affecting_use, check_required_use, human_readable_required_use
 from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
 from portage.output import bold, blue, colorize, create_color_func, darkblue, \
        darkgreen, green, nc_len, red, teal, turquoise, yellow
@@ -2109,13 +2109,27 @@ class depgraph(object):
                                need_enable = sorted(atom.use.enabled.difference(use).intersection(pkg.iuse.all))
                                need_disable = sorted(atom.use.disabled.intersection(use).intersection(pkg.iuse.all))
 
+                               required_use = pkg.metadata["REQUIRED_USE"]
+                               required_use_warning = ""
+                               if required_use:
+                                       old_use = self._pkg_use_enabled(pkg)
+                                       new_use = set(self._pkg_use_enabled(pkg))
+                                       for flag in need_enable:
+                                               new_use.add(flag)
+                                       for flag in need_disable:
+                                               new_use.discard(flag)
+                                       if check_required_use(required_use, old_use, pkg.iuse.is_valid_flag) and \
+                                               not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag):
+                                                       required_use_warning = ", this change violates use flag constraints " + \
+                                                               "defined by %s: '%s'" % (pkg.cpv, human_readable_required_use(required_use))
+
                                if need_enable or need_disable:
                                        changes = []
                                        changes.extend(colorize("red", "+" + x) \
                                                for x in need_enable)
                                        changes.extend(colorize("blue", "-" + x) \
                                                for x in need_disable)
-                                       mreasons.append("Change USE: %s" % " ".join(changes))
+                                       mreasons.append("Change USE: %s" % " ".join(changes) + required_use_warning)
                                        missing_use_reasons.append((pkg, mreasons))
 
                        if not missing_iuse and myparent and atom.unevaluated_atom.use.conditional:
@@ -2123,20 +2137,36 @@ class depgraph(object):
                                # If so, suggest to change them on the parent.
                                mreasons = []
                                violated_atom = atom.unevaluated_atom.violated_conditionals(self._pkg_use_enabled(pkg), \
-                                       pkg.iuse.is_valid_flag, myparent.use.enabled)
+                                       pkg.iuse.is_valid_flag, self._pkg_use_enabled(myparent))
                                if not (violated_atom.use.enabled or violated_atom.use.disabled):
                                        #all violated use deps are conditional
                                        changes = []
                                        conditional = violated_atom.use.conditional
-                                       involved_flags = set()
-                                       involved_flags.update(conditional.equal, conditional.not_equal, \
-                                               conditional.enabled, conditional.disabled)
-                                       for x in involved_flags:
-                                               if x in myparent.use.enabled:
-                                                       changes.append(colorize("blue", "-" + x))
+                                       involved_flags = set(chain(conditional.equal, conditional.not_equal, \
+                                               conditional.enabled, conditional.disabled))
+
+                                       required_use = myparent.metadata["REQUIRED_USE"]
+                                       required_use_warning = ""
+                                       if required_use:
+                                               old_use = self._pkg_use_enabled(myparent)
+                                               new_use = set(self._pkg_use_enabled(myparent))
+                                               for flag in involved_flags:
+                                                       if flag in old_use:
+                                                               new_use.discard(flag)
+                                                       else:
+                                                               new_use.add(flag)
+                                               if check_required_use(required_use, old_use, myparent.iuse.is_valid_flag) and \
+                                                       not check_required_use(required_use, new_use, myparent.iuse.is_valid_flag):
+                                                               required_use_warning = ", this change violates use flag constraints " + \
+                                                                       "defined by %s: '%s'" % (myparent.cpv, \
+                                                                       human_readable_required_use(required_use))
+
+                                       for flag in involved_flags:
+                                               if flag in self._pkg_use_enabled(myparent):
+                                                       changes.append(colorize("blue", "-" + flag))
                                                else:
-                                                       changes.append(colorize("red", "+" + x))
-                                       mreasons.append("Change USE: %s" % " ".join(changes))
+                                                       changes.append(colorize("red", "+" + flag))
+                                       mreasons.append("Change USE: %s" % " ".join(changes) + required_use_warning)
                                        if (myparent, mreasons) not in missing_use_reasons:
                                                missing_use_reasons.append((myparent, mreasons))
 
index 5fa0f79fa22f05cc7cd5f810c52ff0d95e67d8cf..a24e8237a30e2a27b668cd7f02771fe078c51608 100644 (file)
@@ -1659,6 +1659,8 @@ def match_from_list(mydep, candidate_list):
                        mylist.append(x)
        return mylist
 
+def human_readable_required_use(required_use):
+       return required_use.replace("^^", "only-one-of").replace("||", "any-of")
 
 def get_required_use_flags(required_use):
        """
index 929330c3edcd230a286ff1879ca6d834cbb42a8d..df541120d80a9e22debbf5356e07867527e6405e 100644 (file)
@@ -40,6 +40,12 @@ class AutounmaskTestCase(TestCase):
                        "dev-util/Q-1": { "DEPEND": "foo? ( dev-util/R[bar] )", "IUSE": "+foo", "EAPI": 2 },
                        "dev-util/Q-2": { "RDEPEND": "!foo? ( dev-util/R[bar] )", "IUSE": "foo", "EAPI": 2 },
                        "dev-util/R-1": { "IUSE": "bar" },
+
+                       #ebuilds to test interaction with REQUIRED_USE
+                       #~ "app-portage/A-1": { "DEPEND": "app-portage/B[foo]", "EAPI": 2 }, 
+                       #~ "app-portage/A-2": { "DEPEND": "app-portage/B[foo=]", "IUSE": "+foo", "REQUIRED_USE": "foo", "EAPI": 4 }, 
+#~ 
+                       #~ "app-portage/B-1": { "IUSE": "foo +bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": 4 }, 
                        }
 
                test_cases = (
@@ -160,6 +166,18 @@ class AutounmaskTestCase(TestCase):
                                        success = False,
                                        mergelist = ["dev-util/R-1", "dev-util/Q-2"],
                                        use_changes = { "dev-util/R-1": { "bar": True } }),
+
+                               #Test interaction with REQUIRED_USE.
+                               #~ ResolverPlaygroundTestCase(
+                                       #~ ["=app-portage/A-1"],
+                                       #~ options = { "--autounmask": True },
+                                       #~ use_changes = None,
+                                       #~ success = False),
+                               #~ ResolverPlaygroundTestCase(
+                                       #~ ["=app-portage/A-2"],
+                                       #~ options = { "--autounmask": True },
+                                       #~ use_changes = None,
+                                       #~ success = False),
                        )
 
                playground = ResolverPlayground(ebuilds=ebuilds)