| # -*- coding:utf-8 -*- |
| |
| '''keywords.py |
| Perform KEYWORDS related checks |
| ''' |
| |
| |
| class KeywordChecks(object): |
| '''Perform checks on the KEYWORDS of an ebuild''' |
| |
| def __init__(self, qatracker, options): |
| ''' |
| @param qatracker: QATracker instance |
| ''' |
| self.qatracker = qatracker |
| self.options = options |
| self.slot_keywords = {} |
| |
| def prepare(self): |
| '''Prepare the checks for the next package.''' |
| self.slot_keywords = {} |
| |
| def check( |
| self, pkg, package, ebuild, y_ebuild, keywords, ebuild_archs, changed, |
| live_ebuild, kwlist, profiles): |
| '''Perform the check. |
| |
| @param pkg: Package in which we check (object). |
| @param package: Package in which we check (string). |
| @param ebuild: Ebuild which we check (object). |
| @param y_ebuild: Ebuild which we check (string). |
| @param keywords: All the keywords (including -...) of the ebuild. |
| @param ebuild_archs: Just the architectures (no prefixes) of the ebuild. |
| @param changed: Changes instance |
| @param slot_keywords: A dictionary of keywords per slot. |
| @param live_ebuild: A boolean that determines if this is a live ebuild. |
| @param kwlist: A list of all global keywords. |
| @param profiles: A list of all profiles. |
| ''' |
| if not self.options.straight_to_stable: |
| self._checkAddedWithStableKeywords( |
| package, ebuild, y_ebuild, keywords, changed) |
| |
| self._checkForDroppedKeywords( |
| pkg, ebuild, ebuild_archs, live_ebuild) |
| |
| self._checkForInvalidKeywords( |
| pkg, package, y_ebuild, kwlist, profiles) |
| |
| self._checkForMaskLikeKeywords( |
| package, y_ebuild, keywords, kwlist) |
| |
| self.slot_keywords[pkg.slot].update(ebuild_archs) |
| |
| def _isKeywordStable(self, keyword): |
| return not keyword.startswith("~") and not keyword.startswith("-") |
| |
| def _checkAddedWithStableKeywords( |
| self, package, ebuild, y_ebuild, keywords, changed): |
| catdir, pkgdir = package.split("/") |
| |
| stable_keywords = list(filter(self._isKeywordStable, keywords)) |
| if stable_keywords: |
| if ebuild.ebuild_path in changed.new_ebuilds and catdir != "virtual": |
| stable_keywords.sort() |
| self.qatracker.add_error( |
| "KEYWORDS.stable", |
| "%s/%s.ebuild added with stable keywords: %s" % |
| (package, y_ebuild, " ".join(stable_keywords))) |
| |
| def _checkForDroppedKeywords( |
| self, pkg, ebuild, ebuild_archs, live_ebuild): |
| previous_keywords = self.slot_keywords.get(pkg.slot) |
| if previous_keywords is None: |
| self.slot_keywords[pkg.slot] = set() |
| elif ebuild_archs and "*" not in ebuild_archs and not live_ebuild: |
| dropped_keywords = previous_keywords.difference(ebuild_archs) |
| if dropped_keywords: |
| self.qatracker.add_error( |
| "KEYWORDS.dropped", "%s: %s" % ( |
| ebuild.relative_path, |
| " ".join(sorted(dropped_keywords)))) |
| |
| def _checkForInvalidKeywords( |
| self, pkg, package, y_ebuild, kwlist, profiles): |
| myuse = pkg._metadata["KEYWORDS"].split() |
| |
| for mykey in myuse: |
| if mykey not in ("-*", "*", "~*"): |
| myskey = mykey |
| |
| if not self._isKeywordStable(myskey[:1]): |
| myskey = myskey[1:] |
| |
| if myskey not in kwlist: |
| self.qatracker.add_error( |
| "KEYWORDS.invalid", |
| "%s/%s.ebuild: %s" % ( |
| package, y_ebuild, mykey)) |
| elif myskey not in profiles: |
| self.qatracker.add_error( |
| "KEYWORDS.invalid", |
| "%s/%s.ebuild: %s (profile invalid)" % ( |
| package, y_ebuild, mykey)) |
| |
| def _checkForMaskLikeKeywords( |
| self, package, y_ebuild, keywords, kwlist): |
| |
| # KEYWORDS="-*" is a stupid replacement for package.mask |
| # and screws general KEYWORDS semantics |
| if "-*" in keywords: |
| haskeyword = False |
| |
| for kw in keywords: |
| if kw[0] == "~": |
| kw = kw[1:] |
| if kw in kwlist: |
| haskeyword = True |
| |
| if not haskeyword: |
| self.qatracker.add_error( |
| "KEYWORDS.stupid", package + "/" + y_ebuild + ".ebuild") |