From cf10396fdd49b4ca4f72b84ead7dba3c84a127b5 Mon Sep 17 00:00:00 2001 From: Sebastian Luther Date: Tue, 14 Sep 2010 10:41:33 +0200 Subject: config: Add KeywordsManager --- .../package/ebuild/_config/KeywordsManager.py | 184 +++++++++++++++++++++ pym/portage/package/ebuild/config.py | 155 ++--------------- pym/portage/package/ebuild/getmaskingstatus.py | 2 +- 3 files changed, 196 insertions(+), 145 deletions(-) create mode 100644 pym/portage/package/ebuild/_config/KeywordsManager.py diff --git a/pym/portage/package/ebuild/_config/KeywordsManager.py b/pym/portage/package/ebuild/_config/KeywordsManager.py new file mode 100644 index 000000000..b9c223643 --- /dev/null +++ b/pym/portage/package/ebuild/_config/KeywordsManager.py @@ -0,0 +1,184 @@ +# 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 diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py index d920b7e20..f92dd86fb 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -49,6 +49,7 @@ from portage.versions import catpkgsplit, catsplit, cpv_getkey 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 @@ -236,8 +237,7 @@ class config(object): 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 @@ -261,7 +261,6 @@ class config(object): 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) @@ -356,38 +355,6 @@ class config(object): 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 @@ -532,7 +499,6 @@ class config(object): 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) @@ -554,6 +520,10 @@ class config(object): 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. @@ -577,26 +547,6 @@ class config(object): 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) @@ -1489,17 +1439,7 @@ class config(object): 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): """ @@ -1520,84 +1460,11 @@ class config(object): # 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): """ diff --git a/pym/portage/package/ebuild/getmaskingstatus.py b/pym/portage/package/ebuild/getmaskingstatus.py index a09aa33dd..434b4b2eb 100644 --- a/pym/portage/package/ebuild/getmaskingstatus.py +++ b/pym/portage/package/ebuild/getmaskingstatus.py @@ -100,7 +100,7 @@ def _getmaskingstatus(mycpv, settings, portdb): myarch = pgroups[0].lstrip("~") cp = cpv_getkey(mycpv) - pkgdict = settings.pkeywordsdict.get(cp) + pkgdict = settings._keywords_manager.pkeywordsdict.get(cp) matches = False if pkgdict: cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] -- cgit v1.2.3-1-g7c22