--- /dev/null
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'KeywordsManager',
+)
+
+from portage import os
+from portage.dep import ExtendedAtomDict
+from portage.localization import _
+from portage.package.ebuild._config.helper import ordered_by_atom_specificity
+from portage.util import grabdict_package, stack_lists, writemsg
+from portage.versions import cpv_getkey
+
+class KeywordsManager(object):
+
+ def __init__(self, profiles, abs_user_config, user_config=True, global_accept_keywords=""):
+ self._pkeywords_list = []
+ rawpkeywords = [grabdict_package(
+ os.path.join(x, "package.keywords"), recursive=1, verify_eapi=True) \
+ for x in profiles]
+ for pkeyworddict in rawpkeywords:
+ if not pkeyworddict:
+ # Omit non-existent files from the stack. This isn't
+ # feasible for package.use (among other package.*
+ # files such as package.use.mask) since it is stacked
+ # in layers with make.defaults USE, and the layer
+ # indices need to align.
+ continue
+ cpdict = {}
+ for k, v in pkeyworddict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self._pkeywords_list.append(cpdict)
+ self._pkeywords_list = tuple(self._pkeywords_list)
+
+ self._p_accept_keywords = []
+ raw_p_accept_keywords = [grabdict_package(
+ os.path.join(x, "package.accept_keywords"), recursive=1, verify_eapi=True) \
+ for x in profiles]
+ for d in raw_p_accept_keywords:
+ if not d:
+ # Omit non-existent files from the stack.
+ continue
+ cpdict = {}
+ for k, v in d.items():
+ cpdict.setdefault(k.cp, {})[k] = tuple(v)
+ self._p_accept_keywords.append(cpdict)
+ self._p_accept_keywords = tuple(self._p_accept_keywords)
+
+ self.pkeywordsdict = ExtendedAtomDict(dict)
+
+ if user_config:
+ pkgdict = grabdict_package(
+ os.path.join(abs_user_config, "package.keywords"),
+ recursive=1, allow_wildcard=True, verify_eapi=False)
+
+ for k, v in grabdict_package(
+ os.path.join(abs_user_config, "package.accept_keywords"),
+ recursive=1, allow_wildcard=True, verify_eapi=False).items():
+ pkgdict.setdefault(k, []).extend(v)
+
+ accept_keywords_defaults = global_accept_keywords.split()
+ accept_keywords_defaults = tuple('~' + keyword for keyword in \
+ accept_keywords_defaults if keyword[:1] not in "~-")
+ for k, v in pkgdict.items():
+ # default to ~arch if no specific keyword is given
+ if not v:
+ v = accept_keywords_defaults
+ self.pkeywordsdict.setdefault(k.cp, {})[k] = v
+
+ def getKeywords(self, cpv, slot, keywords):
+ cp = cpv_getkey(cpv)
+ pkg = "%s:%s" % (cpv, slot)
+ keywords = [[x for x in keywords.split() if x != "-*"]]
+ for pkeywords_dict in self._pkeywords_list:
+ cpdict = pkeywords_dict.get(cp)
+ if cpdict:
+ pkg_keywords = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_keywords:
+ keywords.extend(pkg_keywords)
+ return stack_lists(keywords, incremental=True)
+
+ def getMissingKeywords(self, cpv, slot, keywords, global_accept_keywords, backuped_accept_keywords):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ may need to accept for the given package. If the KEYWORDS are empty
+ and the the ** keyword has not been accepted, the returned list will
+ contain ** alone (in order to distiguish from the case of "none
+ missing").
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param slot: The 'SLOT' key from the raw package metadata
+ @type slot: String
+ @param keywords: The 'KEYWORDS' key from the raw package metadata
+ @type keywords: String
+ @param global_accept_keywords: The current value of ACCEPT_KEYWORDS
+ @type global_accept_keywords: String
+ @param backuped_accept_keywords: ACCEPT_KEYWORDS from the backup env
+ @type backuped_accept_keywords: String
+ @rtype: List
+ @return: A list of KEYWORDS that have not been accepted.
+ """
+
+ # Hack: Need to check the env directly here as otherwise stacking
+ # doesn't work properly as negative values are lost in the config
+ # object (bug #139600)
+ egroups = backuped_accept_keywords.split()
+ mygroups = self.getKeywords(cpv, slot, keywords)
+ # Repoman may modify this attribute as necessary.
+ pgroups = global_accept_keywords.split()
+ matches = False
+ cp = cpv_getkey(cpv)
+
+ if self._p_accept_keywords:
+ cpv_slot = "%s:%s" % (cpv, slot)
+ accept_keywords_defaults = tuple('~' + keyword for keyword in \
+ pgroups if keyword[:1] not in "~-")
+ for d in self._p_accept_keywords:
+ cpdict = d.get(cp)
+ if cpdict:
+ pkg_accept_keywords = \
+ ordered_by_atom_specificity(cpdict, cpv_slot)
+ if pkg_accept_keywords:
+ for x in pkg_accept_keywords:
+ if not x:
+ x = accept_keywords_defaults
+ pgroups.extend(x)
+ matches = True
+
+ pkgdict = self.pkeywordsdict.get(cp)
+ if pkgdict:
+ cpv_slot = "%s:%s" % (cpv, slot)
+ pkg_accept_keywords = \
+ ordered_by_atom_specificity(pkgdict, cpv_slot)
+ if pkg_accept_keywords:
+ for x in pkg_accept_keywords:
+ pgroups.extend(x)
+ matches = True
+
+ if matches or egroups:
+ pgroups.extend(egroups)
+ inc_pgroups = set()
+ for x in pgroups:
+ if x.startswith("-"):
+ if x == "-*":
+ inc_pgroups.clear()
+ else:
+ inc_pgroups.discard(x[1:])
+ else:
+ inc_pgroups.add(x)
+ pgroups = inc_pgroups
+ del inc_pgroups
+
+ match = False
+ hasstable = False
+ hastesting = False
+ for gp in mygroups:
+ if gp == "*" or (gp == "-*" and len(mygroups) == 1):
+ writemsg(_("--- WARNING: Package '%(cpv)s' uses"
+ " '%(keyword)s' keyword.\n") % {"cpv": cpv, "keyword": gp}, noiselevel=-1)
+ if gp == "*":
+ match = 1
+ break
+ elif gp in pgroups:
+ match=1
+ break
+ elif gp.startswith("~"):
+ hastesting = True
+ elif not gp.startswith("-"):
+ hasstable = True
+ if not match and \
+ ((hastesting and "~*" in pgroups) or \
+ (hasstable and "*" in pgroups) or "**" in pgroups):
+ match=1
+ if match:
+ missing = []
+ else:
+ if not mygroups:
+ # If KEYWORDS is empty then we still have to return something
+ # in order to distiguish from the case of "none missing".
+ mygroups.append("**")
+ missing = mygroups
+ return missing
from portage.package.ebuild._config import special_env_vars
from portage.package.ebuild._config.env_var_validation import validate_cmd_var
from portage.package.ebuild._config.features_set import features_set
+from portage.package.ebuild._config.KeywordsManager import KeywordsManager
from portage.package.ebuild._config.LicenseManager import LicenseManager
from portage.package.ebuild._config.UseManager import UseManager
from portage.package.ebuild._config.LocationsManager import LocationsManager
self._setcpv_args_hash = clone._setcpv_args_hash
# immutable attributes (internal policy ensures lack of mutation)
- self._pkeywords_list = clone._pkeywords_list
- self._p_accept_keywords = clone._p_accept_keywords
+ self._keywords_manager = clone._keywords_manager
self._use_manager = clone._use_manager
self._mask_manager = clone._mask_manager
self.lookuplist.reverse()
self._use_expand_dict = copy.deepcopy(clone._use_expand_dict)
self.backupenv = self.configdict["backupenv"]
- self.pkeywordsdict = copy.deepcopy(clone.pkeywordsdict)
self.prevmaskdict = copy.deepcopy(clone.prevmaskdict)
self.pprovideddict = copy.deepcopy(clone.pprovideddict)
self.features = features_set(self)
x = Atom(x.lstrip('*'))
self.prevmaskdict.setdefault(x.cp, []).append(x)
- self._pkeywords_list = []
- rawpkeywords = [grabdict_package(
- os.path.join(x, "package.keywords"), recursive=1, verify_eapi=True) \
- for x in self.profiles]
- for pkeyworddict in rawpkeywords:
- if not pkeyworddict:
- # Omit non-existent files from the stack. This isn't
- # feasible for package.use (among other package.*
- # files such as package.use.mask) since it is stacked
- # in layers with make.defaults USE, and the layer
- # indices need to align.
- continue
- cpdict = {}
- for k, v in pkeyworddict.items():
- cpdict.setdefault(k.cp, {})[k] = v
- self._pkeywords_list.append(cpdict)
- self._pkeywords_list = tuple(self._pkeywords_list)
-
- self._p_accept_keywords = []
- raw_p_accept_keywords = [grabdict_package(
- os.path.join(x, "package.accept_keywords"), recursive=1, verify_eapi=True) \
- for x in self.profiles]
- for d in raw_p_accept_keywords:
- if not d:
- # Omit non-existent files from the stack.
- continue
- cpdict = {}
- for k, v in d.items():
- cpdict.setdefault(k.cp, {})[k] = tuple(v)
- self._p_accept_keywords.append(cpdict)
- self._p_accept_keywords = tuple(self._p_accept_keywords)
-
# The expand_map is used for variable substitution
# in getconfig() calls, and the getconfig() calls
# update expand_map with the value of each variable
self["PORTAGE_SANDBOX_COMPAT_LEVEL"] = _SANDBOX_COMPAT_LEVEL
self.backup_changes("PORTAGE_SANDBOX_COMPAT_LEVEL")
- self.pkeywordsdict = portage.dep.ExtendedAtomDict(dict)
self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict)
self._penvdict = portage.dep.ExtendedAtomDict(dict)
locations_manager.set_port_dirs(self["PORTDIR"], self["PORTDIR_OVERLAY"])
+ #Read package.keywords and package.accept_keywords.
+ self._keywords_manager = KeywordsManager(self.profiles, abs_user_config, \
+ local_config, global_accept_keywords=self.configdict["defaults"].get("ACCEPT_KEYWORDS", ""))
+
#Read all USE related files from profiles and optionally from user config.
self._use_manager = UseManager(self.profiles, abs_user_config, user_config=local_config)
#Initialize all USE related variables we track ourselves.
self._virtuals_manager = VirtualsManager(self.profiles)
if local_config:
- # package.accept_keywords and package.keywords
- pkgdict = grabdict_package(
- os.path.join(abs_user_config, "package.keywords"),
- recursive=1, allow_wildcard=True, verify_eapi=False)
-
- for k, v in grabdict_package(
- os.path.join(abs_user_config, "package.accept_keywords"),
- recursive=1, allow_wildcard=True, verify_eapi=False).items():
- pkgdict.setdefault(k, []).extend(v)
-
- accept_keywords_defaults = \
- self.configdict["defaults"].get("ACCEPT_KEYWORDS", "").split()
- accept_keywords_defaults = tuple('~' + keyword for keyword in \
- accept_keywords_defaults if keyword[:1] not in "~-")
- for k, v in pkgdict.items():
- # default to ~arch if no specific keyword is given
- if not v:
- v = accept_keywords_defaults
- self.pkeywordsdict.setdefault(k.cp, {})[k] = v
-
#package.properties
propdict = grabdict_package(os.path.join(
abs_user_config, "package.properties"), recursive=1, allow_wildcard=True, verify_eapi=False)
return None
def _getKeywords(self, cpv, metadata):
- cp = cpv_getkey(cpv)
- pkg = "%s:%s" % (cpv, metadata["SLOT"])
- keywords = [[x for x in metadata.get("KEYWORDS", "").split() \
- if x != "-*"]]
- for pkeywords_dict in self._pkeywords_list:
- cpdict = pkeywords_dict.get(cp)
- if cpdict:
- pkg_keywords = ordered_by_atom_specificity(cpdict, pkg)
- if pkg_keywords:
- keywords.extend(pkg_keywords)
- return stack_lists(keywords, incremental=True)
+ return self._keywords_manager.getKeywords(cpv, metadata["SLOT"], metadata.get("KEYWORDS", ""))
def _getMissingKeywords(self, cpv, metadata):
"""
# Hack: Need to check the env directly here as otherwise stacking
# doesn't work properly as negative values are lost in the config
# object (bug #139600)
- egroups = self.configdict["backupenv"].get(
- "ACCEPT_KEYWORDS", "").split()
- mygroups = self._getKeywords(cpv, metadata)
- # Repoman may modify this attribute as necessary.
- pgroups = self["ACCEPT_KEYWORDS"].split()
- matches = False
- cp = cpv_getkey(cpv)
+ backuped_accept_keywords = self.configdict["backupenv"].get("ACCEPT_KEYWORDS", "")
+ global_accept_keywords = self["ACCEPT_KEYWORDS"]
- if self._p_accept_keywords:
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- accept_keywords_defaults = tuple('~' + keyword for keyword in \
- pgroups if keyword[:1] not in "~-")
- for d in self._p_accept_keywords:
- cpdict = d.get(cp)
- if cpdict:
- pkg_accept_keywords = \
- ordered_by_atom_specificity(cpdict, cpv_slot)
- if pkg_accept_keywords:
- for x in pkg_accept_keywords:
- if not x:
- x = accept_keywords_defaults
- pgroups.extend(x)
- matches = True
-
- pkgdict = self.pkeywordsdict.get(cp)
- if pkgdict:
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- pkg_accept_keywords = \
- ordered_by_atom_specificity(pkgdict, cpv_slot)
- if pkg_accept_keywords:
- for x in pkg_accept_keywords:
- pgroups.extend(x)
- matches = True
-
- if matches or egroups:
- pgroups.extend(egroups)
- inc_pgroups = set()
- for x in pgroups:
- if x.startswith("-"):
- if x == "-*":
- inc_pgroups.clear()
- else:
- inc_pgroups.discard(x[1:])
- else:
- inc_pgroups.add(x)
- pgroups = inc_pgroups
- del inc_pgroups
-
- match = False
- hasstable = False
- hastesting = False
- for gp in mygroups:
- if gp == "*" or (gp == "-*" and len(mygroups) == 1):
- writemsg(_("--- WARNING: Package '%(cpv)s' uses"
- " '%(keyword)s' keyword.\n") % {"cpv": cpv, "keyword": gp}, noiselevel=-1)
- if gp == "*":
- match = 1
- break
- elif gp in pgroups:
- match=1
- break
- elif gp.startswith("~"):
- hastesting = True
- elif not gp.startswith("-"):
- hasstable = True
- if not match and \
- ((hastesting and "~*" in pgroups) or \
- (hasstable and "*" in pgroups) or "**" in pgroups):
- match=1
- if match:
- missing = []
- else:
- if not mygroups:
- # If KEYWORDS is empty then we still have to return something
- # in order to distiguish from the case of "none missing".
- mygroups.append("**")
- missing = mygroups
- return missing
+ return self._keywords_manager.getMissingKeywords(cpv, metadata["SLOT"], \
+ metadata.get("KEYWORDS", ""), global_accept_keywords, backuped_accept_keywords)
def _getMissingLicenses(self, cpv, metadata):
"""