EAPI 5 stable use.mask/force for bug #431078
authorZac Medico <zmedico@gentoo.org>
Sat, 25 Aug 2012 04:11:04 +0000 (21:11 -0700)
committerZac Medico <zmedico@gentoo.org>
Sat, 25 Aug 2012 04:11:04 +0000 (21:11 -0700)
pym/_emerge/Package.py
pym/portage/package/ebuild/_config/KeywordsManager.py
pym/portage/package/ebuild/_config/UseManager.py
pym/portage/package/ebuild/config.py
pym/portage/versions.py

index c8a0c9042dc973008936da5d33df10b0c47b8d9a..85fc597736b23eaf4dce210ef35bbb909b3397d9 100644 (file)
@@ -127,6 +127,10 @@ class Package(Task):
                        self._validate_deps()
                return self._validated_atoms
 
+       @property
+       def stable(self):
+               return self.cpv.stable
+
        @classmethod
        def _gen_hash_key(cls, cpv=None, installed=None, onlydeps=None,
                operation=None, repo_name=None, root_config=None,
index 74c7d0a2cb1ebb6ab2534e58b53acf662d643fb4..e42f490aae01b8c26dac5bde3f4bdf35728a090c 100644 (file)
@@ -93,6 +93,33 @@ class KeywordsManager(object):
                                        keywords.extend(pkg_keywords)
                return stack_lists(keywords, incremental=True)
 
+       def isStable(self, pkg, global_accept_keywords, backuped_accept_keywords):
+               mygroups = self.getKeywords(pkg, None, pkg._metadata["KEYWORDS"], None)
+               pgroups = global_accept_keywords.split()
+
+               unmaskgroups = self.getPKeywords(pkg, None, None,
+                       global_accept_keywords)
+               pgroups.extend(unmaskgroups)
+
+               egroups = backuped_accept_keywords.split()
+
+               if unmaskgroups or egroups:
+                       pgroups = self._getEgroups(egroups, pgroups)
+               else:
+                       pgroups = set(pgroups)
+
+               if self._getMissingKeywords(pkg, pgroups, mygroups):
+                       return False
+
+               # If replacing all keywords with unstable variants would mask the
+               # package, then it's not considered stable.
+               unstable = []
+               for kw in mygroups:
+                       if kw[:1] != "~":
+                               kw = "~" + kw
+                       unstable.append(kw)
+
+               return bool(self._getMissingKeywords(pkg, pgroups, set(unstable)))
 
        def getMissingKeywords(self,
                                                        cpv,
index e1ec7f4a01f2f6f775e9bbb628d5e73ac1ffae32..94ff286c84a09903f71b0c27d1ea75c3cdd50443 100644 (file)
@@ -14,6 +14,9 @@ from portage.versions import cpv_getkey, _pkg_str
 
 from portage.package.ebuild._config.helper import ordered_by_atom_specificity
 
+_no_stable_mask_eapis = frozenset(
+       ["0", "1", "2", "3", "4", "4-python", "4-slot-abi"])
+
 class UseManager(object):
 
        def __init__(self, repositories, profiles, abs_user_config, user_config=True):
@@ -56,19 +59,41 @@ class UseManager(object):
                self._repo_puse_dict = self._parse_repository_files_to_dict_of_dicts("package.use", repositories)
 
                self._usemask_list = self._parse_profile_files_to_tuple_of_tuples("use.mask", profiles)
+               self._usestablemask_list = \
+                       self._parse_profile_files_to_tuple_of_tuples("use.stable.mask",
+                               profiles, eapi_filter=self._stable_mask_eapi_filter)
                self._useforce_list = self._parse_profile_files_to_tuple_of_tuples("use.force", profiles)
+               self._usestableforce_list = \
+                       self._parse_profile_files_to_tuple_of_tuples("use.stable.force",
+                               profiles, eapi_filter=self._stable_mask_eapi_filter)
                self._pusemask_list = self._parse_profile_files_to_tuple_of_dicts("package.use.mask", profiles)
+               self._pusestablemask_list = \
+                       self._parse_profile_files_to_tuple_of_dicts("package.use.stable.mask",
+                               profiles, eapi_filter=self._stable_mask_eapi_filter)
                self._pkgprofileuse = self._parse_profile_files_to_tuple_of_dicts("package.use", profiles, juststrings=True)
                self._puseforce_list = self._parse_profile_files_to_tuple_of_dicts("package.use.force", profiles)
+               self._pusestableforce_list = \
+                       self._parse_profile_files_to_tuple_of_dicts("package.use.stable.force",
+                               profiles, eapi_filter=self._stable_mask_eapi_filter)
 
                self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config)
 
                self.repositories = repositories
-       
-       def _parse_file_to_tuple(self, file_name, recursive=True):
+
+       @staticmethod
+       def _stable_mask_eapi_filter(eapi):
+               return eapi not in _no_stable_mask_eapis
+
+       def _parse_file_to_tuple(self, file_name, recursive=True, eapi_filter=None):
                ret = []
                lines = grabfile(file_name, recursive=recursive)
                eapi = read_corresponding_eapi_file(file_name)
+               if eapi_filter is not None and not eapi_filter(eapi):
+                       if lines:
+                               writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") %
+                                       (eapi, os.path.basename(file_name), file_name),
+                                       noiselevel=-1)
+                       return ()
                useflag_re = _get_useflag_re(eapi)
                for prefixed_useflag in lines:
                        if prefixed_useflag[:1] == "-":
@@ -82,11 +107,17 @@ class UseManager(object):
                                ret.append(prefixed_useflag)
                return tuple(ret)
 
-       def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True):
+       def _parse_file_to_dict(self, file_name, juststrings=False, recursive=True, eapi_filter=None):
                ret = {}
                location_dict = {}
                file_dict = grabdict_package(file_name, recursive=recursive, verify_eapi=True)
                eapi = read_corresponding_eapi_file(file_name)
+               if eapi_filter is not None and not eapi_filter(eapi):
+                       if file_dict:
+                               writemsg(_("--- EAPI '%s' does not support '%s': '%s'\n") %
+                                       (eapi, os.path.basename(file_name), file_name),
+                                       noiselevel=-1)
+                       return ret
                useflag_re = _get_useflag_re(eapi)
                for k, v in file_dict.items():
                        useflags = []
@@ -131,16 +162,18 @@ class UseManager(object):
                        ret[repo.name] = self._parse_file_to_dict(os.path.join(repo.location, "profiles", file_name))
                return ret
 
-       def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations):
+       def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations,
+               eapi_filter=None):
                return tuple(self._parse_file_to_tuple(
                        os.path.join(profile.location, file_name),
-                       recursive=profile.portage1_directories)
+                       recursive=profile.portage1_directories, eapi_filter=eapi_filter)
                        for profile in locations)
 
-       def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations, juststrings=False):
+       def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations,
+               juststrings=False, eapi_filter=None):
                return tuple(self._parse_file_to_dict(
                        os.path.join(profile.location, file_name), juststrings,
-                       recursive=profile.portage1_directories)
+                       recursive=profile.portage1_directories, eapi_filter=eapi_filter)
                        for profile in locations)
 
        def getUseMask(self, pkg=None):
@@ -171,14 +204,30 @@ class UseManager(object):
                                        pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
                                        if pkg_usemask:
                                                usemask.extend(pkg_usemask)
+       
+               try:
+                       stable = pkg.stable
+               except AttributeError:
+                       # KEYWORDS is unavailable (prior to "depend" phase)
+                       stable = False
+
                for i, pusemask_dict in enumerate(self._pusemask_list):
                        if self._usemask_list[i]:
                                usemask.append(self._usemask_list[i])
+                       if stable and self._usestablemask_list[i]:
+                               usemask.append(self._usestablemask_list[i])
                        cpdict = pusemask_dict.get(cp)
                        if cpdict:
                                pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
                                if pkg_usemask:
                                        usemask.extend(pkg_usemask)
+                       if stable:
+                               cpdict = self._pusestablemask_list[i].get(cp)
+                               if cpdict:
+                                       pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
+                                       if pkg_usemask:
+                                               usemask.extend(pkg_usemask)
+
                return frozenset(stack_lists(usemask, incremental=True))
 
        def getUseForce(self, pkg=None):
@@ -205,14 +254,30 @@ class UseManager(object):
                                        pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
                                        if pkg_useforce:
                                                useforce.extend(pkg_useforce)
+
+               try:
+                       stable = pkg.stable
+               except AttributeError:
+                       # KEYWORDS is unavailable (prior to "depend" phase)
+                       stable = False
+
                for i, puseforce_dict in enumerate(self._puseforce_list):
                        if self._useforce_list[i]:
                                useforce.append(self._useforce_list[i])
+                       if stable and self._usestableforce_list[i]:
+                               useforce.append(self._usestableforce_list[i])
                        cpdict = puseforce_dict.get(cp)
                        if cpdict:
                                pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
                                if pkg_useforce:
                                        useforce.extend(pkg_useforce)
+                       if stable:
+                               cpdict = self._pusestableforce_list[i].get(cp)
+                               if cpdict:
+                                       pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
+                                       if pkg_useforce:
+                                               useforce.extend(pkg_useforce)
+
                return frozenset(stack_lists(useforce, incremental=True))
 
        def getPUSE(self, pkg):
index 94c0bbc797aad84a38456326324b49393c4575b6..871831fb67a382b822b469ba6445093473271d95 100644 (file)
@@ -1653,6 +1653,11 @@ class config(object):
                                return x
                return None
 
+       def _isStable(self, pkg):
+               return self._keywords_manager.isStable(pkg,
+                       self.get("ACCEPT_KEYWORDS", ""),
+                       self.configdict["backupenv"].get("ACCEPT_KEYWORDS", ""))
+
        def _getKeywords(self, cpv, metadata):
                return self._keywords_manager.getKeywords(cpv, metadata["SLOT"], \
                        metadata.get("KEYWORDS", ""), metadata.get("repository"))
index 36eb8ac2127d4408ff164c28e3139b3be365dfb9..692256b24cdbb4a989c11f923f10884909b46d9f 100644 (file)
@@ -396,6 +396,20 @@ class _pkg_str(_unicode):
                raise AttributeError("_pkg_str instances are immutable",
                        self.__class__, name, value)
 
+       @property
+       def stable(self):
+               try:
+                       return self._stable
+               except AttributeError:
+                       try:
+                               metadata = self._metadata
+                               settings = self._settings
+                       except AttributeError:
+                               raise AttributeError('stable')
+                       stable = settings._isStable(self)
+                       self.__dict__['_stable'] = stable
+                       return stable
+
 def pkgsplit(mypkg, silent=1, eapi=None):
        """
        @param mypkg: either a pv or cpv