diff options
Diffstat (limited to 'lib/portage/dbapi/__init__.py')
-rw-r--r-- | lib/portage/dbapi/__init__.py | 113 |
1 files changed, 59 insertions, 54 deletions
diff --git a/lib/portage/dbapi/__init__.py b/lib/portage/dbapi/__init__.py index 717ab95d5..9105227c7 100644 --- a/lib/portage/dbapi/__init__.py +++ b/lib/portage/dbapi/__init__.py @@ -1,10 +1,14 @@ -# Copyright 1998-2020 Gentoo Authors +# Copyright 1998-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 __all__ = ["dbapi"] import functools +import logging import re +import sys +from typing import Any, Dict, List, Optional, Tuple +from collections.abc import Sequence import portage @@ -22,14 +26,18 @@ from portage.const import MERGING_IDENTIFIER from portage import os from portage import auxdbkeys from portage.eapi import _get_eapi_attrs -from portage.exception import InvalidData +from portage.exception import ( + CorruptionKeyError, + InvalidBinaryPackageFormat, + InvalidData, +) from portage.localization import _ from _emerge.Package import Package class dbapi: _category_re = re.compile(r"^\w[-.+\w]*$", re.UNICODE) - _categories = None + _categories: Optional[tuple[str, ...]] = None _use_mutable = False _known_keys = frozenset(auxdbkeys) _pkg_str_aux_keys = ("EAPI", "KEYWORDS", "SLOT", "repository") @@ -38,7 +46,7 @@ class dbapi: pass @property - def categories(self): + def categories(self) -> tuple[str, ...]: """ Use self.cp_all() to generate a category list. Mutable instances can delete the self._categories attribute in cases when the cached @@ -46,17 +54,17 @@ class dbapi: """ if self._categories is not None: return self._categories - self._categories = tuple(sorted(set(catsplit(x)[0] for x in self.cp_all()))) + self._categories = tuple(sorted({catsplit(x)[0] for x in self.cp_all()})) return self._categories def close_caches(self): pass - def cp_list(self, cp, use_cache=1): + def cp_list(self, cp: str, use_cache: int = 1) -> Any: raise NotImplementedError(self) @staticmethod - def _cmp_cpv(cpv1, cpv2): + def _cmp_cpv(cpv1, cpv2) -> int: result = vercmp(cpv1.version, cpv2.version) if result == 0 and cpv1.build_time is not None and cpv2.build_time is not None: result = (cpv1.build_time > cpv2.build_time) - ( @@ -65,7 +73,7 @@ class dbapi: return result @staticmethod - def _cpv_sort_ascending(cpv_list): + def _cpv_sort_ascending(cpv_list: Sequence[Any]) -> None: """ Use this to sort self.cp_list() results in ascending order. It sorts in place and returns None. @@ -76,7 +84,7 @@ class dbapi: # dict to map strings back to their original values. cpv_list.sort(key=cmp_sort_key(dbapi._cmp_cpv)) - def cpv_all(self): + def cpv_all(self) -> list[str]: """Return all CPVs in the db Args: None @@ -93,16 +101,18 @@ class dbapi: cpv_list.extend(self.cp_list(cp)) return cpv_list - def cp_all(self, sort=False): + def cp_all(self, sort: bool = False) -> list[str]: """Implement this in a child class Args sort - return sorted results Returns: A list of strings 1 per CP in the datastore """ - return NotImplementedError + raise NotImplementedError - def aux_get(self, mycpv, mylist, myrepo=None): + def aux_get( + self, mycpv: str, mylist: str, myrepo: Optional[str] = None + ) -> list[str]: """Return the metadata keys in mylist for mycpv Args: mycpv - "sys-apps/foo-1.0" @@ -114,7 +124,7 @@ class dbapi: """ raise NotImplementedError - def aux_update(self, cpv, metadata_updates): + def aux_update(self, cpv: str, metadata_updates: dict[str, Any]) -> None: """ Args: cpv - "sys-apps/foo-1.0" @@ -124,7 +134,7 @@ class dbapi: """ raise NotImplementedError - def match(self, origdep, use_cache=1): + def match(self, origdep: str, use_cache: int = 1): """Given a dependency, try to find packages that match Args: origdep - Depend atom @@ -138,7 +148,7 @@ class dbapi: self._iter_match(mydep, self.cp_list(mydep.cp, use_cache=use_cache)) ) - def _iter_match(self, atom, cpv_iter): + def _iter_match(self, atom: str, cpv_iter): cpv_iter = iter(match_from_list(atom, cpv_iter)) if atom.repo: cpv_iter = self._iter_match_repo(atom, cpv_iter) @@ -150,7 +160,7 @@ class dbapi: def _pkg_str(self, cpv, repo): """ - This is used to contruct _pkg_str instances on-demand during + This is used to construct _pkg_str instances on-demand during matching. If cpv is a _pkg_str instance with slot attribute, then simply return it. Otherwise, fetch metadata and construct a _pkg_str instance. This may raise KeyError or InvalidData. @@ -219,17 +229,9 @@ class dbapi: yield cpv - def _repoman_iuse_implicit_cnstr(self, pkg, metadata): - """ - In repoman's version of _iuse_implicit_cnstr, account for modifications - of the self.settings reference between calls. - """ - eapi_attrs = _get_eapi_attrs(metadata["EAPI"]) - if eapi_attrs.iuse_effective: - iuse_implicit_match = lambda flag: self.settings._iuse_effective_match(flag) - else: - iuse_implicit_match = lambda flag: self.settings._iuse_implicit_match(flag) - return iuse_implicit_match + @staticmethod + def _iuse_implicit_built(iuse_implicit_match, use, flag): + return iuse_implicit_match(flag) or flag in use def _iuse_implicit_cnstr(self, pkg, metadata): """ @@ -265,25 +267,25 @@ class dbapi: # This behavior is only used for EAPIs that support IUSE_EFFECTIVE, # since built USE settings for earlier EAPIs may contain a large # number of irrelevant flags. - prof_iuse = iuse_implicit_match - enabled = frozenset(metadata["USE"].split()).__contains__ - iuse_implicit_match = lambda flag: prof_iuse(flag) or enabled(flag) + iuse_implicit_match = functools.partial( + self._iuse_implicit_built, + iuse_implicit_match, + frozenset(metadata["USE"].split()), + ) return iuse_implicit_match def _match_use(self, atom, pkg, metadata, ignore_profile=False): iuse_implicit_match = self._iuse_implicit_cnstr(pkg, metadata) - usealiases = self.settings._use_manager.getUseAliases(pkg) iuse = Package._iuse( None, metadata["IUSE"].split(), iuse_implicit_match, - usealiases, metadata["EAPI"], ) for x in atom.unevaluated_atom.use.required: - if iuse.get_real_flag(x) is None: + if iuse.get_flag(x) is None: return False if atom.use is None: @@ -297,18 +299,16 @@ class dbapi: # with implicit IUSE, in order to avoid potential # inconsistencies in USE dep matching (see bug #453400). use = frozenset( - x for x in metadata["USE"].split() if iuse.get_real_flag(x) is not None + x for x in metadata["USE"].split() if iuse.get_flag(x) is not None ) missing_enabled = frozenset( - x for x in atom.use.missing_enabled if iuse.get_real_flag(x) is None + x for x in atom.use.missing_enabled if iuse.get_flag(x) is None ) missing_disabled = frozenset( - x for x in atom.use.missing_disabled if iuse.get_real_flag(x) is None - ) - enabled = frozenset((iuse.get_real_flag(x) or x) for x in atom.use.enabled) - disabled = frozenset( - (iuse.get_real_flag(x) or x) for x in atom.use.disabled + x for x in atom.use.missing_disabled if iuse.get_flag(x) is None ) + enabled = frozenset((iuse.get_flag(x) or x) for x in atom.use.enabled) + disabled = frozenset((iuse.get_flag(x) or x) for x in atom.use.disabled) if enabled: if any(x in enabled for x in missing_disabled): @@ -333,7 +333,7 @@ class dbapi: pkg, stable=self.settings._parent_stable ) if any( - x in usemask and iuse.get_real_flag(x) is not None + x in usemask and iuse.get_flag(x) is not None for x in atom.use.enabled ): return False @@ -342,9 +342,7 @@ class dbapi: pkg, stable=self.settings._parent_stable ) if any( - x in useforce - and x not in usemask - and iuse.get_real_flag(x) is not None + x in useforce and x not in usemask and iuse.get_flag(x) is not None for x in atom.use.disabled ): return False @@ -352,15 +350,13 @@ class dbapi: # Check unsatisfied use-default deps if atom.use.enabled: missing_disabled = frozenset( - x - for x in atom.use.missing_disabled - if iuse.get_real_flag(x) is None + x for x in atom.use.missing_disabled if iuse.get_flag(x) is None ) if any(x in atom.use.enabled for x in missing_disabled): return False if atom.use.disabled: missing_enabled = frozenset( - x for x in atom.use.missing_enabled if iuse.get_real_flag(x) is None + x for x in atom.use.missing_enabled if iuse.get_flag(x) is None ) if any(x in atom.use.disabled for x in missing_enabled): return False @@ -371,11 +367,11 @@ class dbapi: if "/" + MERGING_IDENTIFIER in mypath: if os.path.exists(mypath): writemsg( - colorize("BAD", _("INCOMPLETE MERGE:")) + " %s\n" % mypath, + colorize("BAD", _("INCOMPLETE MERGE:")) + f" {mypath}\n", noiselevel=-1, ) else: - writemsg("!!! Invalid db entry: %s\n" % mypath, noiselevel=-1) + writemsg(f"!!! Invalid db entry: {mypath}\n", noiselevel=-1) def update_ents(self, updates, onProgress=None, onUpdate=None): """ @@ -412,7 +408,7 @@ class dbapi: pkg = _pkg_str(cpv, metadata=metadata, settings=self.settings) except InvalidData: continue - metadata = dict((k, metadata[k]) for k in update_keys) + metadata = {k: metadata[k] for k in update_keys} if repo_dict is None: updates_list = updates else: @@ -431,7 +427,12 @@ class dbapi: updates_list, metadata, parent=pkg ) if metadata_updates: - aux_update(cpv, metadata_updates) + try: + aux_update(cpv, metadata_updates) + except (InvalidBinaryPackageFormat, CorruptionKeyError) as e: + logging.warning( + f"{e.__class__.__name__}: {e}", exc_info=sys.exc_info() + ) if onUpdate: onUpdate(maxval, i + 1) if onProgress: @@ -474,7 +475,11 @@ class dbapi: and mycpv.sub_slot and mycpv.sub_slot not in (mycpv.slot, newslot) ): - newslot = "%s/%s" % (newslot, mycpv.sub_slot) + newslot = f"{newslot}/{mycpv.sub_slot}" mydata = {"SLOT": newslot + "\n"} - self.aux_update(mycpv, mydata) + try: + self.aux_update(mycpv, mydata) + except CorruptionKeyError as e: + logging.warning(f"{e.__class__.__name__}: {e}", exc_info=sys.exc_info()) + continue return moves |