--autounmask: Allow package.mask changes
authorSebastian Luther <SebastianLuther@gmx.de>
Sun, 15 May 2011 19:03:20 +0000 (12:03 -0700)
committerZac Medico <zmedico@gentoo.org>
Sun, 15 May 2011 19:03:20 +0000 (12:03 -0700)
pym/_emerge/depgraph.py
pym/_emerge/resolver/backtracking.py
pym/portage/package/ebuild/getmaskingstatus.py
pym/portage/tests/resolver/ResolverPlayground.py
pym/portage/tests/resolver/test_autounmask.py

index 8558436bb44acd3eb3b3a29f9c7fcc86437e1d10..d095ce1898ea24814d6893a37d5d00d71880395d 100644 (file)
@@ -413,6 +413,7 @@ class _dynamic_depgraph_config(object):
                self._highest_pkg_cache = {}
 
                self._needed_unstable_keywords = backtrack_parameters.needed_unstable_keywords
+               self._needed_p_mask_changes = backtrack_parameters.needed_p_mask_changes
                self._needed_license_changes = backtrack_parameters.needed_license_changes
                self._needed_use_config_changes = backtrack_parameters.needed_use_config_changes
                self._runtime_pkg_mask = backtrack_parameters.runtime_pkg_mask
@@ -2289,6 +2290,8 @@ class depgraph(object):
                if set(self._dynamic_config.digraph).intersection( \
                        self._dynamic_config._needed_unstable_keywords) or \
                        set(self._dynamic_config.digraph).intersection( \
+                       self._dynamic_config._needed_p_mask_changes) or \
+                       set(self._dynamic_config.digraph).intersection( \
                        self._dynamic_config._needed_use_config_changes) or \
                        set(self._dynamic_config.digraph).intersection( \
                        self._dynamic_config._needed_license_changes) :
@@ -3278,17 +3281,22 @@ class depgraph(object):
                                if pkg is not None:
                                        break
 
-                               pkg, existing = \
-                                       self._wrapped_select_pkg_highest_available_imp(
-                                               root, atom, onlydeps=onlydeps,
-                                               allow_use_changes=True,
-                                               allow_unstable_keywords=(not only_use_changes),
-                                               allow_license_changes=(not only_use_changes))
-
-                               if pkg is not None and \
-                                       pkg.installed and \
-                                       not self._want_installed_pkg(pkg):
-                                       pkg = None
+                               for allow_unmasks in (False, True):
+                                       if only_use_changes and allow_unmasks:
+                                               continue
+
+                                       pkg, existing = \
+                                               self._wrapped_select_pkg_highest_available_imp(
+                                                       root, atom, onlydeps=onlydeps,
+                                                       allow_use_changes=True,
+                                                       allow_unstable_keywords=(not only_use_changes),
+                                                       allow_license_changes=(not only_use_changes),
+                                                       allow_unmasks=allow_unmasks)
+
+                                       if pkg is not None and \
+                                               pkg.installed and \
+                                               not self._want_installed_pkg(pkg):
+                                               pkg = None
                        
                        if self._dynamic_config._need_restart:
                                return None, None
@@ -3300,7 +3308,7 @@ class depgraph(object):
 
                return pkg, existing
 
-       def _pkg_visibility_check(self, pkg, allow_unstable_keywords=False, allow_license_changes=False):
+       def _pkg_visibility_check(self, pkg, allow_unstable_keywords=False, allow_license_changes=False, allow_unmasks=False):
 
                if pkg.visible:
                        return True
@@ -3315,6 +3323,7 @@ class depgraph(object):
                masked_by_unstable_keywords = False
                missing_licenses = None
                masked_by_something_else = False
+               masked_by_p_mask = False
 
                for reason in mreasons:
                        hint = reason.unmask_hint
@@ -3323,6 +3332,8 @@ class depgraph(object):
                                masked_by_something_else = True
                        elif hint.key == "unstable keyword":
                                masked_by_unstable_keywords = True
+                       elif hint.key == "p_mask":
+                               masked_by_p_mask = True
                        elif hint.key == "license":
                                missing_licenses = hint.value
                        else:
@@ -3335,15 +3346,20 @@ class depgraph(object):
                        #If the package is already keyworded, remove the mask.
                        masked_by_unstable_keywords = False
 
+               if pkg in self._dynamic_config._needed_p_mask_changes:
+                       #If the package is already keyworded, remove the mask.
+                       masked_by_p_mask = False
+
                if missing_licenses:
                        #If the needed licenses are already unmasked, remove the mask.
                        missing_licenses.difference_update(self._dynamic_config._needed_license_changes.get(pkg, set()))
 
-               if not (masked_by_unstable_keywords or missing_licenses):
+               if not (masked_by_unstable_keywords or masked_by_p_mask or missing_licenses):
                        #Package has already been unmasked.
                        return True
 
                if (masked_by_unstable_keywords and not allow_unstable_keywords) or \
+                       (masked_by_p_mask and not allow_unmasks) or \
                        (missing_licenses and not allow_license_changes):
                        #We are not allowed to do the needed changes.
                        return False
@@ -3354,7 +3370,13 @@ class depgraph(object):
                        backtrack_infos.setdefault("config", {})
                        backtrack_infos["config"].setdefault("needed_unstable_keywords", set())
                        backtrack_infos["config"]["needed_unstable_keywords"].add(pkg)
-                       
+
+               if masked_by_p_mask:
+                       self._dynamic_config._needed_p_mask_changes.add(pkg)
+                       backtrack_infos = self._dynamic_config._backtrack_infos
+                       backtrack_infos.setdefault("config", {})
+                       backtrack_infos["config"].setdefault("needed_p_mask_changes", set())
+                       backtrack_infos["config"]["needed_p_mask_changes"].add(pkg)
 
                if missing_licenses:
                        self._dynamic_config._needed_license_changes.setdefault(pkg, set()).update(missing_licenses)
@@ -3452,7 +3474,7 @@ class depgraph(object):
                return new_use
 
        def _wrapped_select_pkg_highest_available_imp(self, root, atom, onlydeps=False, \
-               allow_use_changes=False, allow_unstable_keywords=False, allow_license_changes=False):
+               allow_use_changes=False, allow_unstable_keywords=False, allow_license_changes=False, allow_unmasks=False):
                root_config = self._frozen_config.roots[root]
                pkgsettings = self._frozen_config.pkgsettings[root]
                dbs = self._dynamic_config._filtered_trees[root]["dbs"]
@@ -3588,7 +3610,8 @@ class depgraph(object):
 
                                                if not self._pkg_visibility_check(pkg, \
                                                        allow_unstable_keywords=allow_unstable_keywords,
-                                                       allow_license_changes=allow_license_changes):
+                                                       allow_license_changes=allow_license_changes,
+                                                       allow_unmasks=allow_unmasks):
                                                        continue
 
                                                # Enable upgrade or downgrade to a version
@@ -3630,7 +3653,8 @@ class depgraph(object):
                                                                                        "ebuild", Atom("=%s" % (pkg.cpv,))):
                                                                                        if self._pkg_visibility_check(pkg_eb, \
                                                                                                allow_unstable_keywords=allow_unstable_keywords,
-                                                                                               allow_license_changes=allow_license_changes):
+                                                                                               allow_license_changes=allow_license_changes,
+                                                                                               allow_unmasks=allow_unmasks):
                                                                                                pkg_eb_visible = True
                                                                                                break
                                                                                if not pkg_eb_visible:
@@ -3638,7 +3662,8 @@ class depgraph(object):
                                                                        else:
                                                                                if not self._pkg_visibility_check(pkg_eb, \
                                                                                        allow_unstable_keywords=allow_unstable_keywords,
-                                                                                       allow_license_changes=allow_license_changes):
+                                                                                       allow_license_changes=allow_license_changes,
+                                                                                       allow_unmasks=allow_unmasks):
                                                                                        continue
 
                                        # Calculation of USE for unbuilt ebuilds is relatively
@@ -3882,18 +3907,19 @@ class depgraph(object):
                                for pkg in matched_packages:
                                        if pkg.installed and self._pkg_visibility_check(pkg, \
                                                allow_unstable_keywords=allow_unstable_keywords,
-                                               allow_license_changes=allow_license_changes):
+                                               allow_license_changes=allow_license_changes,
+                                               allow_unmasks=allow_unmasks):
                                                return pkg, existing_node
 
                        visible_matches = []
                        if matched_oldpkg:
                                visible_matches = [pkg.cpv for pkg in matched_oldpkg \
                                        if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
-                                               allow_license_changes=allow_license_changes)]
+                                               allow_license_changes=allow_license_changes, allow_unmasks=allow_unmasks)]
                        if not visible_matches:
                                visible_matches = [pkg.cpv for pkg in matched_packages \
                                        if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
-                                               allow_license_changes=allow_license_changes)]
+                                               allow_license_changes=allow_license_changes, allow_unmasks=allow_unmasks)]
                        if visible_matches:
                                bestmatch = portage.best(visible_matches)
                        else:
@@ -5557,6 +5583,30 @@ class depgraph(object):
                                                else:
                                                        unstable_keyword_msg[root].append("=%s %s\n" % (pkg.cpv, keyword))
 
+               p_mask_change_msg = {}
+               for pkg in self._dynamic_config._needed_p_mask_changes:
+                       self._show_merge_list()
+                       if pkg in self._dynamic_config.digraph:
+                               root = pkg.root
+                               roots.add(root)
+                               p_mask_change_msg.setdefault(root, [])
+                               is_latest, is_latest_in_slot = check_if_latest(pkg)
+                               pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+                               mreasons = _get_masking_status(pkg, pkgsettings, pkg.root_config,
+                                       use=self._pkg_use_enabled(pkg))
+                               for reason in mreasons:
+                                       if reason.unmask_hint and \
+                                               reason.unmask_hint.key == 'p_mask':
+                                               keyword = reason.unmask_hint.value
+
+                                               p_mask_change_msg[root].append(self._get_dep_chain_as_comment(pkg))
+                                               if is_latest:
+                                                       p_mask_change_msg[root].append(">=%s\n" % pkg.cpv)
+                                               elif is_latest_in_slot:
+                                                       p_mask_change_msg[root].append(">=%s:%s\n" % (pkg.cpv, pkg.metadata["SLOT"]))
+                                               else:
+                                                       p_mask_change_msg[root].append("=%s\n" % pkg.cpv)
+
                use_changes_msg = {}
                for pkg, needed_use_config_change in self._dynamic_config._needed_use_config_changes.items():
                        self._show_merge_list()
@@ -5633,6 +5683,10 @@ class depgraph(object):
                                        file_to_write_to[(abs_user_config, "package.keywords")] = \
                                                find_config_file(abs_user_config, "package.keywords")
 
+                               if root in p_mask_change_msg:
+                                       file_to_write_to[(abs_user_config, "package.unmask")] = \
+                                               find_config_file(abs_user_config, "package.unmask")
+
                                if root in use_changes_msg:
                                        file_to_write_to[(abs_user_config, "package.use")] = \
                                                find_config_file(abs_user_config, "package.use")
@@ -5687,6 +5741,10 @@ class depgraph(object):
                                write_changes(root, "keyword", unstable_keyword_msg[root],
                                        file_to_write_to.get((abs_user_config, "package.keywords")))
 
+                       if root in p_mask_change_msg:
+                               write_changes(root, "mask", p_mask_change_msg[root],
+                                       file_to_write_to.get((abs_user_config, "package.unmask")))
+
                        if root in use_changes_msg:
                                write_changes(root, "USE", use_changes_msg[root],
                                        file_to_write_to.get((abs_user_config, "package.use")))
index 3c40bd8df5c27e8cc540b92a0bb93fcf401ee492..dcdaee0cb97bedef0a5da77d0952f2b940f98896 100644 (file)
@@ -7,11 +7,12 @@ class BacktrackParameter(object):
 
        __slots__ = (
                "needed_unstable_keywords", "runtime_pkg_mask", "needed_use_config_changes", "needed_license_changes",
-               "rebuild_list", "reinstall_list"
+               "rebuild_list", "reinstall_list", "needed_p_mask_changes"
        )
 
        def __init__(self):
                self.needed_unstable_keywords = set()
+               self.needed_p_mask_changes = set()
                self.runtime_pkg_mask = {}
                self.needed_use_config_changes = {}
                self.needed_license_changes = {}
@@ -27,6 +28,7 @@ class BacktrackParameter(object):
                #Shallow copies are enough here, as we only need to ensure that nobody adds stuff
                #to our sets and dicts. The existing content is immutable.
                result.needed_unstable_keywords = copy.copy(self.needed_unstable_keywords)
+               result.needed_p_mask_changes = copy.copy(self.needed_p_mask_changes)
                result.runtime_pkg_mask = copy.copy(self.runtime_pkg_mask)
                result.needed_use_config_changes = copy.copy(self.needed_use_config_changes)
                result.needed_license_changes = copy.copy(self.needed_license_changes)
@@ -37,6 +39,7 @@ class BacktrackParameter(object):
 
        def __eq__(self, other):
                return self.needed_unstable_keywords == other.needed_unstable_keywords and \
+                       self.needed_p_mask_changes == other.needed_p_mask_changes and \
                        self.runtime_pkg_mask == other.runtime_pkg_mask and \
                        self.needed_use_config_changes == other.needed_use_config_changes and \
                        self.needed_license_changes == other.needed_license_changes and \
@@ -138,6 +141,8 @@ class Backtracker(object):
                for change, data in changes.items():
                        if change == "needed_unstable_keywords":
                                para.needed_unstable_keywords.update(data)
+                       elif change == "needed_p_mask_changes":
+                               para.needed_p_mask_changes.update(data)
                        elif change == "needed_license_changes":
                                for pkg, missing_licenses in data:
                                        para.needed_license_changes.setdefault(pkg, set()).update(missing_licenses)
index a7d3c333f95af8436875bf7c10c1874219e01015..e46f7886db5e8cce6438fe311a6bdf2ff557dac3 100644 (file)
@@ -77,7 +77,7 @@ def _getmaskingstatus(mycpv, settings, portdb, myrepo=None):
 
        # package.mask checking
        if settings._getMaskAtom(mycpv, metadata):
-               rValue.append(_MaskReason("package.mask", "package.mask"))
+               rValue.append(_MaskReason("package.mask", "package.mask", _UnmaskHint("p_mask", None)))
 
        # keywords checking
        eapi = metadata["EAPI"]
index c3540c939df929e4b97e7feee415e5ef9700d891..f5bd77ff2b91e5dafffc4f872d14809abc0ce952 100644 (file)
@@ -516,7 +516,7 @@ class ResolverPlaygroundTestCase(object):
                                if self.ignore_mergelist_order and got is not None:
                                        got = set(got)
                                        expected = set(expected)
-                       elif key == "unstable_keywords" and expected is not None:
+                       elif key in ("unstable_keywords", "needed_p_mask_changes") and expected is not None:
                                expected = set(expected)
 
                        if got != expected:
@@ -532,7 +532,7 @@ class ResolverPlaygroundResult(object):
 
        checks = (
                "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
-               "circular_dependency_solutions",
+               "circular_dependency_solutions", "needed_p_mask_changes",
                )
        optional_checks = (
                )
@@ -546,6 +546,7 @@ class ResolverPlaygroundResult(object):
                self.use_changes = None
                self.license_changes = None
                self.unstable_keywords = None
+               self.needed_p_mask_changes = None
                self.slot_collision_solutions = None
                self.circular_dependency_solutions = None
 
@@ -572,6 +573,11 @@ class ResolverPlaygroundResult(object):
                        for pkg in self.depgraph._dynamic_config._needed_unstable_keywords:
                                self.unstable_keywords.add(pkg.cpv)
 
+               if self.depgraph._dynamic_config._needed_p_mask_changes:
+                       self.needed_p_mask_changes = set()
+                       for pkg in self.depgraph._dynamic_config._needed_p_mask_changes:
+                               self.needed_p_mask_changes.add(pkg.cpv)
+
                if self.depgraph._dynamic_config._needed_license_changes:
                        self.license_changes = {}
                        for pkg, missing_licenses in self.depgraph._dynamic_config._needed_license_changes.items():
index 027eb33266bf79dca5d954a9a274121e5bf493ec..62b1522338c733301fde78e22abd73d3e90e1b23 100644 (file)
@@ -29,6 +29,10 @@ class AutounmaskTestCase(TestCase):
                        "app-misc/W-2": { "KEYWORDS": "~x86" },
                        "app-misc/V-1": { "KEYWORDS": "~x86", "DEPEND": ">=app-misc/W-2"},
 
+                       #ebuilds to test mask and keyword changes
+                       "app-text/A-1": {},
+                       "app-text/B-1": { "KEYWORDS": "~x86" },
+
                        #ebuilds for mixed test for || dep handling
                        "sci-libs/K-1": { "DEPEND": " || ( sci-libs/L[bar] || ( sci-libs/M sci-libs/P ) )", "EAPI": 2},
                        "sci-libs/K-2": { "DEPEND": " || ( sci-libs/L[bar] || ( sci-libs/P sci-libs/M ) )", "EAPI": 2},
@@ -203,6 +207,21 @@ class AutounmaskTestCase(TestCase):
                                        options = {"--autounmask": True},
                                        use_changes = None,
                                        success = False),
+
+                               #Test mask and keyword changes.
+                               ResolverPlaygroundTestCase(
+                                       ["app-text/A"],
+                                       options = {"--autounmask": True},
+                                       success = False,
+                                       mergelist = ["app-text/A-1"],
+                                       needed_p_mask_changes = ["app-text/A-1"]),
+                               ResolverPlaygroundTestCase(
+                                       ["app-text/B"],
+                                       options = {"--autounmask": True},
+                                       success = False,
+                                       mergelist = ["app-text/B-1"],
+                                       unstable_keywords = ["app-text/B-1"],
+                                       needed_p_mask_changes = ["app-text/B-1"]),
                        )
 
                profile = {
@@ -214,6 +233,11 @@ class AutounmaskTestCase(TestCase):
                                (
                                        "forced-flag",
                                ),
+                       "package.mask":
+                               (
+                                       "app-text/A",
+                                       "app-text/B",
+                               ),
                }
 
                playground = ResolverPlayground(ebuilds=ebuilds, profile=profile)