autounmask: Avoid unmasking live versions if possible
authorSebastian Luther <SebastianLuther@gmx.de>
Sun, 26 Feb 2012 09:34:31 +0000 (10:34 +0100)
committerZac Medico <zmedico@gentoo.org>
Sun, 26 Feb 2012 09:59:00 +0000 (01:59 -0800)
Before this patch the allowed changes were:

1. USE
2. USE + ~arch + license
3. USE + ~arch + license + missing keywords + masks

With this patch:

1. USE
2. USE + ~arch + license
3. USE + ~arch + license + missing keywords
4. USE + ~arch + license + masks
5. USE + ~arch + license + missing keywords + masks

This avoids unmasking live versions, which are typically masked
and have missing keywords to be avoided if there is a regular
masked version available.

pym/_emerge/depgraph.py
pym/portage/tests/resolver/test_autounmask.py

index a05c17e93e4c86762e04fb80384eb6249db2e0f9..e4310b480edcbd2767bc9b5a1976459069ca29ff 100644 (file)
@@ -3505,15 +3505,31 @@ class depgraph(object):
                return True
 
        class _AutounmaskLevel(object):
-               __slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", "allow_unmasks")
+               __slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", \
+                       "allow_missing_keywords", "allow_unmasks")
 
                def __init__(self):
                        self.allow_use_changes = False
-                       self.allow_unstable_keywords = False
                        self.allow_license_changes = False
+                       self.allow_unstable_keywords = False
+                       self.allow_missing_keywords = False
                        self.allow_unmasks = False
 
        def _autounmask_levels(self):
+               """
+               Iterate over the different allowed things to unmask.
+
+               1. USE
+               2. USE + ~arch + license
+               3. USE + ~arch + license + missing keywords
+               4. USE + ~arch + license + masks
+               5. USE + ~arch + license + missing keywords + masks
+
+               Some thoughts:
+                       * Do least invasive changes first.
+                       * Try unmasking alone before unmasking + missing keywords
+                               to avoid -9999 versions if possible
+               """
 
                if self._dynamic_config._autounmask is not True:
                        return
@@ -3528,11 +3544,13 @@ class depgraph(object):
                        autounmask_level.allow_unstable_keywords = (not only_use_changes)
                        autounmask_level.allow_license_changes = (not only_use_changes)
 
-                       for allow_unmasks in (False, True):
-                               if allow_unmasks and (only_use_changes or autounmask_keep_masks):
-                                       continue
+                       for missing_keyword, unmask in ((False,False), (True, False), (False, True), (True, True)):
+
+                               if (only_use_changes or autounmask_keep_masks) and (missing_keyword or unmask):
+                                       break
 
-                               autounmask_level.allow_unmasks = allow_unmasks
+                               autounmask_level.allow_missing_keywords = missing_keyword
+                               autounmask_level.allow_unmasks = unmask
 
                                yield autounmask_level
 
@@ -3634,9 +3652,8 @@ class depgraph(object):
                        #Package has already been unmasked.
                        return True
 
-               #We treat missing keywords in the same way as masks.
                if (masked_by_unstable_keywords and not autounmask_level.allow_unstable_keywords) or \
-                       (masked_by_missing_keywords and not autounmask_level.allow_unmasks) or \
+                       (masked_by_missing_keywords and not autounmask_level.allow_missing_keywords) or \
                        (masked_by_p_mask and not autounmask_level.allow_unmasks) or \
                        (missing_licenses and not autounmask_level.allow_license_changes):
                        #We are not allowed to do the needed changes.
index 3da1c25105df32073a16816a4a9de43e38969d6e..46dbab18e0bf0ee9f7299b0ba96160ba8e7c6b1f 100644 (file)
@@ -391,7 +391,11 @@ class AutounmaskTestCase(TestCase):
 
 
        def testAutounmaskKeepMasks(self):
-
+               """
+               Ensure that we try to use a masked version with keywords before trying
+               masked version with missing keywords (prefer masked regular version
+               over -9999 version).
+               """
                ebuilds = {
                        "app-text/A-1": {},
                        }
@@ -427,3 +431,44 @@ class AutounmaskTestCase(TestCase):
                                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
                finally:
                        playground.cleanup()
+
+
+       def testAutounmask9999(self):
+
+               ebuilds = {
+                       "dev-libs/A-1": { },
+                       "dev-libs/A-2": { },
+                       "dev-libs/A-9999": { "KEYWORDS": "" },
+                       "dev-libs/B-1": { "DEPEND": ">=dev-libs/A-2" },
+                       "dev-libs/C-1": { "DEPEND": ">=dev-libs/A-3" },
+                       }
+
+               profile = {
+                       "package.mask":
+                               (
+                                       ">=dev-libs/A-2",
+                               ),
+               }
+
+               test_cases = (
+                       ResolverPlaygroundTestCase(
+                               ["dev-libs/B"],
+                               success = False,
+                               mergelist = ["dev-libs/A-2", "dev-libs/B-1"],
+                               needed_p_mask_changes = set(["dev-libs/A-2"])),
+
+                       ResolverPlaygroundTestCase(
+                               ["dev-libs/C"],
+                               success = False,
+                               mergelist = ["dev-libs/A-9999", "dev-libs/C-1"],
+                               unstable_keywords = set(["dev-libs/A-9999"]),
+                               needed_p_mask_changes = set(["dev-libs/A-9999"])),
+                       )
+
+               playground = ResolverPlayground(ebuilds=ebuilds, profile=profile)
+               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()