diff options
Diffstat (limited to 'portage_with_autodep/pym/portage/dbapi/porttree.py')
-rw-r--r-- | portage_with_autodep/pym/portage/dbapi/porttree.py | 694 |
1 files changed, 332 insertions, 362 deletions
diff --git a/portage_with_autodep/pym/portage/dbapi/porttree.py b/portage_with_autodep/pym/portage/dbapi/porttree.py index ecf275c..c5ee770 100644 --- a/portage_with_autodep/pym/portage/dbapi/porttree.py +++ b/portage_with_autodep/pym/portage/dbapi/porttree.py @@ -1,4 +1,4 @@ -# Copyright 1998-2011 Gentoo Foundation +# Copyright 1998-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 __all__ = [ @@ -14,20 +14,19 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.package.ebuild.doebuild:doebuild', 'portage.util:ensure_dirs,shlex_split,writemsg,writemsg_level', 'portage.util.listdir:listdir', - 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp', + 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp,_pkg_str', ) -from portage.cache import metadata_overlay, volatile +from portage.cache import volatile from portage.cache.cache_errors import CacheError from portage.cache.mappings import Mapping from portage.dbapi import dbapi from portage.exception import PortageException, \ FileNotFound, InvalidAtom, InvalidDependString, InvalidPackageName from portage.localization import _ -from portage.manifest import Manifest -from portage import eclass_cache, auxdbkeys, \ - eapi_is_supported, dep_check, \ +from portage import eclass_cache, \ + eapi_is_supported, \ _eapi_is_deprecated from portage import os from portage import _encodings @@ -37,8 +36,6 @@ from _emerge.EbuildMetadataPhase import EbuildMetadataPhase from _emerge.PollScheduler import PollScheduler import os as _os -import io -import stat import sys import traceback import warnings @@ -47,15 +44,6 @@ if sys.hexversion >= 0x3000000: basestring = str long = int -class _repo_info(object): - __slots__ = ('name', 'path', 'eclass_db', 'portdir', 'portdir_overlay') - def __init__(self, name, path, eclass_db): - self.name = name - self.path = path - self.eclass_db = eclass_db - self.portdir = eclass_db.porttrees[0] - self.portdir_overlay = ' '.join(eclass_db.porttrees[1:]) - class portdbapi(dbapi): """this tree will scan a portage directory located at root (passed to init)""" portdbapi_instances = [] @@ -69,6 +57,13 @@ class portdbapi(dbapi): def porttree_root(self): return self.settings.repositories.mainRepoLocation() + @property + def eclassdb(self): + main_repo = self.repositories.mainRepo() + if main_repo is None: + return None + return main_repo.eclass_db + def __init__(self, _unused_param=None, mysettings=None): """ @param _unused_param: deprecated, use mysettings['PORTDIR'] instead @@ -100,6 +95,7 @@ class portdbapi(dbapi): # this purpose because doebuild makes many changes to the config # instance that is passed in. self.doebuild_settings = config(clone=self.settings) + self._scheduler = PollScheduler().sched_iface self.depcachedir = os.path.realpath(self.settings.depcachedir) if os.environ.get("SANDBOX_ON") == "1": @@ -112,7 +108,6 @@ class portdbapi(dbapi): ":".join(filter(None, sandbox_write)) self.porttrees = list(self.settings.repositories.repoLocationList()) - self.eclassdb = eclass_cache.cache(self.settings.repositories.mainRepoLocation()) # This is used as sanity check for aux_get(). If there is no # root eclass dir, we assume that PORTDIR is invalid or @@ -121,86 +116,74 @@ class portdbapi(dbapi): self._have_root_eclass_dir = os.path.isdir( os.path.join(self.settings.repositories.mainRepoLocation(), "eclass")) - self.metadbmodule = self.settings.load_best_module("portdbapi.metadbmodule") - #if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening) self.xcache = {} self.frozen = 0 - #Create eclass dbs - self._repo_info = {} - eclass_dbs = {self.settings.repositories.mainRepoLocation() : self.eclassdb} - for repo in self.repositories: - if repo.location in self._repo_info: - continue - - eclass_db = None - for eclass_location in repo.eclass_locations: - tree_db = eclass_dbs.get(eclass_location) - if tree_db is None: - tree_db = eclass_cache.cache(eclass_location) - eclass_dbs[eclass_location] = tree_db - if eclass_db is None: - eclass_db = tree_db.copy() - else: - eclass_db.append(tree_db) - - self._repo_info[repo.location] = _repo_info(repo.name, repo.location, eclass_db) - #Keep a list of repo names, sorted by priority (highest priority first). self._ordered_repo_name_list = tuple(reversed(self.repositories.prepos_order)) self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule") self.auxdb = {} self._pregen_auxdb = {} + # If the current user doesn't have depcachedir write permission, + # then the depcachedir cache is kept here read-only access. + self._ro_auxdb = {} self._init_cache_dirs() - depcachedir_w_ok = os.access(self.depcachedir, os.W_OK) - cache_kwargs = { - 'gid' : portage_gid, - 'perms' : 0o664 - } - - # XXX: REMOVE THIS ONCE UNUSED_0 IS YANKED FROM auxdbkeys - # ~harring - filtered_auxdbkeys = [x for x in auxdbkeys if not x.startswith("UNUSED_0")] - filtered_auxdbkeys.sort() + try: + depcachedir_st = os.stat(self.depcachedir) + depcachedir_w_ok = os.access(self.depcachedir, os.W_OK) + except OSError: + depcachedir_st = None + depcachedir_w_ok = False + + cache_kwargs = {} + + depcachedir_unshared = False + if portage.data.secpass < 1 and \ + depcachedir_w_ok and \ + depcachedir_st is not None and \ + os.getuid() == depcachedir_st.st_uid and \ + os.getgid() == depcachedir_st.st_gid: + # If this user owns depcachedir and is not in the + # portage group, then don't bother to set permissions + # on cache entries. This makes it possible to run + # egencache without any need to be a member of the + # portage group. + depcachedir_unshared = True + else: + cache_kwargs.update({ + 'gid' : portage_gid, + 'perms' : 0o664 + }) + # If secpass < 1, we don't want to write to the cache # since then we won't be able to apply group permissions # to the cache entries/directories. - if secpass < 1 or not depcachedir_w_ok: + if (secpass < 1 and not depcachedir_unshared) or not depcachedir_w_ok: for x in self.porttrees: + self.auxdb[x] = volatile.database( + self.depcachedir, x, self._known_keys, + **cache_kwargs) try: - db_ro = self.auxdbmodule(self.depcachedir, x, - filtered_auxdbkeys, readonly=True, **cache_kwargs) + self._ro_auxdb[x] = self.auxdbmodule(self.depcachedir, x, + self._known_keys, readonly=True, **cache_kwargs) except CacheError: - self.auxdb[x] = volatile.database( - self.depcachedir, x, filtered_auxdbkeys, - **cache_kwargs) - else: - self.auxdb[x] = metadata_overlay.database( - self.depcachedir, x, filtered_auxdbkeys, - db_rw=volatile.database, db_ro=db_ro, - **cache_kwargs) + pass else: for x in self.porttrees: if x in self.auxdb: continue # location, label, auxdbkeys self.auxdb[x] = self.auxdbmodule( - self.depcachedir, x, filtered_auxdbkeys, **cache_kwargs) - if self.auxdbmodule is metadata_overlay.database: - self.auxdb[x].db_ro.ec = self._repo_info[x].eclass_db + self.depcachedir, x, self._known_keys, **cache_kwargs) if "metadata-transfer" not in self.settings.features: for x in self.porttrees: if x in self._pregen_auxdb: continue - if os.path.isdir(os.path.join(x, "metadata", "cache")): - self._pregen_auxdb[x] = self.metadbmodule( - x, "metadata/cache", filtered_auxdbkeys, readonly=True) - try: - self._pregen_auxdb[x].ec = self._repo_info[x].eclass_db - except AttributeError: - pass + cache = self._create_pregen_cache(x) + if cache is not None: + self._pregen_auxdb[x] = cache # Selectively cache metadata in order to optimize dep matching. self._aux_cache_keys = set( ["DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE", @@ -210,18 +193,28 @@ class portdbapi(dbapi): self._aux_cache = {} self._broken_ebuilds = set() + def _create_pregen_cache(self, tree): + conf = self.repositories.get_repo_for_location(tree) + cache = conf.get_pregenerated_cache( + self._known_keys, readonly=True) + if cache is not None: + try: + cache.ec = self.repositories.get_repo_for_location(tree).eclass_db + except AttributeError: + pass + return cache + def _init_cache_dirs(self): """Create /var/cache/edb/dep and adjust permissions for the portage group.""" dirmode = 0o2070 - filemode = 0o60 modemask = 0o2 try: ensure_dirs(self.depcachedir, gid=portage_gid, mode=dirmode, mask=modemask) - except PortageException as e: + except PortageException: pass def close_caches(self): @@ -260,7 +253,7 @@ class portdbapi(dbapi): @param canonical_repo_path: the canonical path of a repository, as resolved by os.path.realpath() @type canonical_repo_path: String - @returns: The repo_name for the corresponding repository, or None + @return: The repo_name for the corresponding repository, or None if the path does not correspond a known repository @rtype: String or None """ @@ -332,63 +325,33 @@ class portdbapi(dbapi): return (filename, x) return (None, 0) - def _metadata_process(self, cpv, ebuild_path, repo_path): - """ - Create an EbuildMetadataPhase instance to generate metadata for the - give ebuild. - @rtype: EbuildMetadataPhase - @returns: A new EbuildMetadataPhase instance, or None if the - metadata cache is already valid. - """ - metadata, st, emtime = self._pull_valid_cache(cpv, ebuild_path, repo_path) - if metadata is not None: - return None - - process = EbuildMetadataPhase(cpv=cpv, ebuild_path=ebuild_path, - ebuild_mtime=emtime, metadata_callback=self._metadata_callback, - portdb=self, repo_path=repo_path, settings=self.doebuild_settings) - return process - - def _metadata_callback(self, cpv, ebuild_path, repo_path, metadata, mtime): - - i = metadata - if hasattr(metadata, "items"): - i = iter(metadata.items()) - metadata = dict(i) - - if metadata.get("INHERITED", False): - metadata["_eclasses_"] = self._repo_info[repo_path - ].eclass_db.get_eclass_data(metadata["INHERITED"].split()) - else: - metadata["_eclasses_"] = {} - - metadata.pop("INHERITED", None) - metadata["_mtime_"] = mtime - - eapi = metadata.get("EAPI") - if not eapi or not eapi.strip(): - eapi = "0" - metadata["EAPI"] = eapi - if not eapi_is_supported(eapi): - for k in set(metadata).difference(("_mtime_", "_eclasses_")): - metadata[k] = "" - metadata["EAPI"] = "-" + eapi.lstrip("-") + def _write_cache(self, cpv, repo_path, metadata, ebuild_hash): try: - self.auxdb[repo_path][cpv] = metadata + cache = self.auxdb[repo_path] + chf = cache.validation_chf + metadata['_%s_' % chf] = getattr(ebuild_hash, chf) except CacheError: # Normally this shouldn't happen, so we'll show # a traceback for debugging purposes. traceback.print_exc() - return metadata + cache = None + + if cache is not None: + try: + cache[cpv] = metadata + except CacheError: + # Normally this shouldn't happen, so we'll show + # a traceback for debugging purposes. + traceback.print_exc() def _pull_valid_cache(self, cpv, ebuild_path, repo_path): try: - # Don't use unicode-wrapped os module, for better performance. - st = _os.stat(_unicode_encode(ebuild_path, - encoding=_encodings['fs'], errors='strict')) - emtime = st[stat.ST_MTIME] - except OSError: + ebuild_hash = eclass_cache.hashed_path(ebuild_path) + # snag mtime since we use it later, and to trigger stat failure + # if it doesn't exist + ebuild_hash.mtime + except FileNotFound: writemsg(_("!!! aux_get(): ebuild for " \ "'%s' does not exist at:\n") % (cpv,), noiselevel=-1) writemsg("!!! %s\n" % ebuild_path, noiselevel=-1) @@ -401,39 +364,39 @@ class portdbapi(dbapi): pregen_auxdb = self._pregen_auxdb.get(repo_path) if pregen_auxdb is not None: auxdbs.append(pregen_auxdb) + ro_auxdb = self._ro_auxdb.get(repo_path) + if ro_auxdb is not None: + auxdbs.append(ro_auxdb) auxdbs.append(self.auxdb[repo_path]) - eclass_db = self._repo_info[repo_path].eclass_db + eclass_db = self.repositories.get_repo_for_location(repo_path).eclass_db - doregen = True for auxdb in auxdbs: try: metadata = auxdb[cpv] except KeyError: - pass + continue except CacheError: - if auxdb is not pregen_auxdb: + if not auxdb.readonly: try: del auxdb[cpv] - except KeyError: - pass - except CacheError: + except (KeyError, CacheError): pass - else: - eapi = metadata.get('EAPI', '').strip() - if not eapi: - eapi = '0' - if not (eapi[:1] == '-' and eapi_is_supported(eapi[1:])) and \ - emtime == metadata['_mtime_'] and \ - eclass_db.is_eclass_data_valid(metadata['_eclasses_']): - doregen = False - - if not doregen: + continue + eapi = metadata.get('EAPI', '').strip() + if not eapi: + eapi = '0' + metadata['EAPI'] = eapi + if not eapi_is_supported(eapi): + # Since we're supposed to be able to efficiently obtain the + # EAPI from _parse_eapi_ebuild_head, we disregard cache entries + # for unsupported EAPIs. + continue + if auxdb.validate_entry(metadata, ebuild_hash, eclass_db): break - - if doregen: + else: metadata = None - return (metadata, st, emtime) + return (metadata, ebuild_hash) def aux_get(self, mycpv, mylist, mytree=None, myrepo=None): "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc." @@ -445,15 +408,22 @@ class portdbapi(dbapi): if mytree is None: raise KeyError(myrepo) - if not mytree: + if mytree is not None and len(self.porttrees) == 1 \ + and mytree == self.porttrees[0]: + # mytree matches our only tree, so it's safe to + # ignore mytree and cache the result + mytree = None + myrepo = None + + if mytree is None: cache_me = True - if not mytree and not self._known_keys.intersection( + if mytree is None and not self._known_keys.intersection( mylist).difference(self._aux_cache_keys): aux_cache = self._aux_cache.get(mycpv) if aux_cache is not None: return [aux_cache.get(x, "") for x in mylist] cache_me = True - global auxdbkeys, auxdbkeylen + try: cat, pkg = mycpv.split("/", 1) except ValueError: @@ -467,60 +437,35 @@ class portdbapi(dbapi): _("ebuild not found for '%s'") % mycpv, noiselevel=1) raise KeyError(mycpv) - mydata, st, emtime = self._pull_valid_cache(mycpv, myebuild, mylocation) + mydata, ebuild_hash = self._pull_valid_cache(mycpv, myebuild, mylocation) doregen = mydata is None if doregen: if myebuild in self._broken_ebuilds: raise KeyError(mycpv) - self.doebuild_settings.setcpv(mycpv) - eapi = None - - if eapi is None and \ - 'parse-eapi-ebuild-head' in self.doebuild_settings.features: - eapi = portage._parse_eapi_ebuild_head(io.open( - _unicode_encode(myebuild, - encoding=_encodings['fs'], errors='strict'), - mode='r', encoding=_encodings['repo.content'], - errors='replace')) - - if eapi is not None: - self.doebuild_settings.configdict['pkg']['EAPI'] = eapi - - if eapi is not None and not portage.eapi_is_supported(eapi): - mydata = self._metadata_callback( - mycpv, myebuild, mylocation, {'EAPI':eapi}, emtime) - else: - proc = EbuildMetadataPhase(cpv=mycpv, ebuild_path=myebuild, - ebuild_mtime=emtime, - metadata_callback=self._metadata_callback, portdb=self, - repo_path=mylocation, - scheduler=PollScheduler().sched_iface, - settings=self.doebuild_settings) + proc = EbuildMetadataPhase(cpv=mycpv, + ebuild_hash=ebuild_hash, portdb=self, + repo_path=mylocation, scheduler=self._scheduler, + settings=self.doebuild_settings) - proc.start() - proc.wait() + proc.start() + proc.wait() - if proc.returncode != os.EX_OK: - self._broken_ebuilds.add(myebuild) - raise KeyError(mycpv) + if proc.returncode != os.EX_OK: + self._broken_ebuilds.add(myebuild) + raise KeyError(mycpv) - mydata = proc.metadata + mydata = proc.metadata - # do we have a origin repository name for the current package mydata["repository"] = self.repositories.get_name_for_location(mylocation) - mydata["INHERITED"] = ' '.join(mydata.get("_eclasses_", [])) - mydata["_mtime_"] = st[stat.ST_MTIME] - + mydata["_mtime_"] = ebuild_hash.mtime eapi = mydata.get("EAPI") if not eapi: eapi = "0" mydata["EAPI"] = eapi - if not eapi_is_supported(eapi): - for k in set(mydata).difference(("_mtime_", "_eclasses_")): - mydata[k] = "" - mydata["EAPI"] = "-" + eapi.lstrip("-") + if eapi_is_supported(eapi): + mydata["INHERITED"] = " ".join(mydata.get("_eclasses_", [])) #finally, we look at our internal cache entry and return the requested data. returnme = [mydata.get(x, "") for x in mylist] @@ -546,7 +491,7 @@ class portdbapi(dbapi): @param mytree: The canonical path of the tree in which the ebuild is located, or None for automatic lookup @type mypkg: String - @returns: A dict which maps each file name to a set of alternative + @return: A dict which maps each file name to a set of alternative URIs. @rtype: dict """ @@ -565,7 +510,7 @@ class portdbapi(dbapi): # since callers already handle it. raise portage.exception.InvalidDependString( "getFetchMap(): '%s' has unsupported EAPI: '%s'" % \ - (mypkg, eapi.lstrip("-"))) + (mypkg, eapi)) return _parse_uri_map(mypkg, {'EAPI':eapi,'SRC_URI':myuris}, use=useflags) @@ -576,7 +521,9 @@ class portdbapi(dbapi): if myebuild is None: raise AssertionError(_("ebuild not found for '%s'") % mypkg) pkgdir = os.path.dirname(myebuild) - mf = Manifest(pkgdir, self.settings["DISTDIR"]) + mf = self.repositories.get_repo_for_location( + os.path.dirname(os.path.dirname(pkgdir))).load_manifest( + pkgdir, self.settings["DISTDIR"]) checksums = mf.getDigests() if not checksums: if debug: @@ -597,7 +544,7 @@ class portdbapi(dbapi): mystat = None try: mystat = os.stat(file_path) - except OSError as e: + except OSError: pass if mystat is None: existing_size = 0 @@ -644,7 +591,9 @@ class portdbapi(dbapi): if myebuild is None: raise AssertionError(_("ebuild not found for '%s'") % mypkg) pkgdir = os.path.dirname(myebuild) - mf = Manifest(pkgdir, self.settings["DISTDIR"]) + mf = self.repositories.get_repo_for_location( + os.path.dirname(os.path.dirname(pkgdir))) + mf = mf.load_manifest(pkgdir, self.settings["DISTDIR"]) mysums = mf.getDigests() failures = {} @@ -706,15 +655,22 @@ class portdbapi(dbapi): return l def cp_list(self, mycp, use_cache=1, mytree=None): + # NOTE: Cache can be safely shared with the match cache, since the + # match cache uses the result from dep_expand for the cache_key. + if self.frozen and mytree is not None \ + and len(self.porttrees) == 1 \ + and mytree == self.porttrees[0]: + # mytree matches our only tree, so it's safe to + # ignore mytree and cache the result + mytree = None + if self.frozen and mytree is None: cachelist = self.xcache["cp-list"].get(mycp) if cachelist is not None: # Try to propagate this to the match-all cache here for # repoman since he uses separate match-all caches for each - # profile (due to old-style virtuals). Do not propagate - # old-style virtuals since cp_list() doesn't expand them. - if not (not cachelist and mycp.startswith("virtual/")): - self.xcache["match-all"][mycp] = cachelist + # profile (due to differences in _get_implicit_iuse). + self.xcache["match-all"][(mycp, mycp)] = cachelist return cachelist[:] mysplit = mycp.split("/") invalid_category = mysplit[0] not in self._categories @@ -752,7 +708,7 @@ class portdbapi(dbapi): writemsg(_("\nInvalid ebuild version: %s\n") % \ os.path.join(oroot, mycp, x), noiselevel=-1) continue - d[mysplit[0]+"/"+pf] = None + d[_pkg_str(mysplit[0]+"/"+pf)] = None if invalid_category and d: writemsg(_("\n!!! '%s' has a category that is not listed in " \ "%setc/portage/categories\n") % \ @@ -766,14 +722,11 @@ class portdbapi(dbapi): if self.frozen and mytree is None: cachelist = mylist[:] self.xcache["cp-list"][mycp] = cachelist - # Do not propagate old-style virtuals since - # cp_list() doesn't expand them. - if not (not cachelist and mycp.startswith("virtual/")): - self.xcache["match-all"][mycp] = cachelist + self.xcache["match-all"][(mycp, mycp)] = cachelist return mylist def freeze(self): - for x in "bestmatch-visible", "cp-list", "list-visible", "match-all", \ + for x in "bestmatch-visible", "cp-list", "match-all", \ "match-all-cpv-only", "match-visible", "minimum-all", \ "minimum-visible": self.xcache[x]={} @@ -785,12 +738,12 @@ class portdbapi(dbapi): def xmatch(self,level,origdep,mydep=None,mykey=None,mylist=None): "caching match function; very trick stuff" - #if no updates are being made to the tree, we can consult our xcache... - if self.frozen: - try: - return self.xcache[level][origdep][:] - except KeyError: - pass + if level == "list-visible": + level = "match-visible" + warnings.warn("The 'list-visible' mode of " + "portage.dbapi.porttree.portdbapi.xmatch " + "has been renamed to match-visible", + DeprecationWarning, stacklevel=2) if mydep is None: #this stuff only runs on first call of xmatch() @@ -798,12 +751,24 @@ class portdbapi(dbapi): mydep = dep_expand(origdep, mydb=self, settings=self.settings) mykey = mydep.cp + #if no updates are being made to the tree, we can consult our xcache... + cache_key = None + if self.frozen: + cache_key = (mydep, mydep.unevaluated_atom) + try: + return self.xcache[level][cache_key][:] + except KeyError: + pass + myval = None mytree = None if mydep.repo is not None: mytree = self.treemap.get(mydep.repo) if mytree is None: - myval = [] + if level.startswith("match-"): + myval = [] + else: + myval = "" if myval is not None: # Unknown repo, empty result. @@ -822,27 +787,8 @@ class portdbapi(dbapi): myval = match_from_list(mydep, self.cp_list(mykey, mytree=mytree)) - elif level == "list-visible": - #a list of all visible packages, not called directly (just by xmatch()) - #myval = self.visible(self.cp_list(mykey)) - - myval = self.gvisible(self.visible( - self.cp_list(mykey, mytree=mytree))) - elif level == "minimum-all": - # Find the minimum matching version. This is optimized to - # minimize the number of metadata accesses (improves performance - # especially in cases where metadata needs to be generated). - if mydep == mykey: - cpv_iter = iter(self.cp_list(mykey, mytree=mytree)) - else: - cpv_iter = self._iter_match(mydep, - self.cp_list(mykey, mytree=mytree)) - try: - myval = next(cpv_iter) - except StopIteration: - myval = "" - - elif level in ("minimum-visible", "bestmatch-visible"): + elif level in ("bestmatch-visible", "match-all", "match-visible", + "minimum-all", "minimum-visible"): # Find the minimum matching visible version. This is optimized to # minimize the number of metadata accesses (improves performance # especially in cases where metadata needs to be generated). @@ -851,158 +797,172 @@ class portdbapi(dbapi): else: mylist = match_from_list(mydep, self.cp_list(mykey, mytree=mytree)) - myval = "" - settings = self.settings - local_config = settings.local_config + + visibility_filter = level not in ("match-all", "minimum-all") + single_match = level not in ("match-all", "match-visible") + myval = [] aux_keys = list(self._aux_cache_keys) - if level == "minimum-visible": + if level == "bestmatch-visible": + iterfunc = reversed + else: iterfunc = iter + + if mydep.repo is not None: + repos = [mydep.repo] else: - iterfunc = reversed + # We iterate over self.porttrees, since it's common to + # tweak this attribute in order to adjust match behavior. + repos = [] + for tree in reversed(self.porttrees): + repos.append(self.repositories.get_name_for_location(tree)) + for cpv in iterfunc(mylist): - try: - metadata = dict(zip(aux_keys, - self.aux_get(cpv, aux_keys))) - except KeyError: - # ebuild masked by corruption - continue - if not eapi_is_supported(metadata["EAPI"]): - continue - if mydep.slot and mydep.slot != metadata["SLOT"]: - continue - if settings._getMissingKeywords(cpv, metadata): - continue - if settings._getMaskAtom(cpv, metadata): - continue - if settings._getProfileMaskAtom(cpv, metadata): - continue - if local_config: - metadata["USE"] = "" - if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]: - self.doebuild_settings.setcpv(cpv, mydb=metadata) - metadata["USE"] = self.doebuild_settings.get("USE", "") + for repo in repos: try: - if settings._getMissingLicenses(cpv, metadata): - continue - if settings._getMissingProperties(cpv, metadata): - continue - except InvalidDependString: + metadata = dict(zip(aux_keys, + self.aux_get(cpv, aux_keys, myrepo=repo))) + except KeyError: + # ebuild not in this repo, or masked by corruption continue - if mydep.use: - has_iuse = False - for has_iuse in self._iter_match_use(mydep, [cpv]): - break - if not has_iuse: + + if visibility_filter and not self._visible(cpv, metadata): continue - myval = cpv - break + + if mydep.slot is not None and \ + mydep.slot != metadata["SLOT"]: + continue + + if mydep.unevaluated_atom.use is not None and \ + not self._match_use(mydep, cpv, metadata): + continue + + myval.append(cpv) + # only yield a given cpv once + break + + if myval and single_match: + break + + if single_match: + if myval: + myval = myval[0] + else: + myval = "" + elif level == "bestmatch-list": #dep match -- find best match but restrict search to sublist - #no point in calling xmatch again since we're not caching list deps - + warnings.warn("The 'bestmatch-list' mode of " + "portage.dbapi.porttree.portdbapi.xmatch is deprecated", + DeprecationWarning, stacklevel=2) myval = best(list(self._iter_match(mydep, mylist))) elif level == "match-list": #dep match -- find all matches but restrict search to sublist (used in 2nd half of visible()) - + warnings.warn("The 'match-list' mode of " + "portage.dbapi.porttree.portdbapi.xmatch is deprecated", + DeprecationWarning, stacklevel=2) myval = list(self._iter_match(mydep, mylist)) - elif level == "match-visible": - #dep match -- find all visible matches - #get all visible packages, then get the matching ones - myval = list(self._iter_match(mydep, - self.xmatch("list-visible", mykey, mydep=Atom(mykey), mykey=mykey))) - elif level == "match-all": - #match *all* visible *and* masked packages - if mydep == mykey: - myval = self.cp_list(mykey, mytree=mytree) - else: - myval = list(self._iter_match(mydep, - self.cp_list(mykey, mytree=mytree))) else: raise AssertionError( "Invalid level argument: '%s'" % level) - if self.frozen and (level not in ["match-list", "bestmatch-list"]): - self.xcache[level][mydep] = myval - if origdep and origdep != mydep: - self.xcache[level][origdep] = myval - return myval[:] + if self.frozen: + xcache_this_level = self.xcache.get(level) + if xcache_this_level is not None: + xcache_this_level[cache_key] = myval + if not isinstance(myval, _pkg_str): + myval = myval[:] + + return myval def match(self, mydep, use_cache=1): return self.xmatch("match-visible", mydep) - def visible(self, mylist): - """two functions in one. Accepts a list of cpv values and uses the package.mask *and* - packages file to remove invisible entries, returning remaining items. This function assumes - that all entries in mylist have the same category and package name.""" - if not mylist: - return [] - - db_keys = ["SLOT"] - visible = [] - getMaskAtom = self.settings._getMaskAtom - getProfileMaskAtom = self.settings._getProfileMaskAtom - for cpv in mylist: - try: - metadata = dict(zip(db_keys, self.aux_get(cpv, db_keys))) - except KeyError: - # masked by corruption - continue - if not metadata["SLOT"]: - continue - if getMaskAtom(cpv, metadata): - continue - if getProfileMaskAtom(cpv, metadata): - continue - visible.append(cpv) - return visible - - def gvisible(self,mylist): - "strip out group-masked (not in current group) entries" + def gvisible(self, mylist): + warnings.warn("The 'gvisible' method of " + "portage.dbapi.porttree.portdbapi " + "is deprecated", + DeprecationWarning, stacklevel=2) + return list(self._iter_visible(iter(mylist))) - if mylist is None: + def visible(self, cpv_iter): + warnings.warn("The 'visible' method of " + "portage.dbapi.porttree.portdbapi " + "is deprecated", + DeprecationWarning, stacklevel=2) + if cpv_iter is None: return [] - newlist=[] + return list(self._iter_visible(iter(cpv_iter))) + + def _iter_visible(self, cpv_iter, myrepo=None): + """ + Return a new list containing only visible packages. + """ aux_keys = list(self._aux_cache_keys) metadata = {} - local_config = self.settings.local_config - chost = self.settings.get('CHOST', '') - accept_chost = self.settings._accept_chost - for mycpv in mylist: - metadata.clear() - try: - metadata.update(zip(aux_keys, self.aux_get(mycpv, aux_keys))) - except KeyError: - continue - except PortageException as e: - writemsg("!!! Error: aux_get('%s', %s)\n" % (mycpv, aux_keys), - noiselevel=-1) - writemsg("!!! %s\n" % (e,), noiselevel=-1) - del e - continue - eapi = metadata["EAPI"] - if not eapi_is_supported(eapi): - continue - if _eapi_is_deprecated(eapi): - continue - if self.settings._getMissingKeywords(mycpv, metadata): - continue - if local_config: - metadata['CHOST'] = chost - if not accept_chost(mycpv, metadata): - continue - metadata["USE"] = "" - if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]: - self.doebuild_settings.setcpv(mycpv, mydb=metadata) - metadata['USE'] = self.doebuild_settings['PORTAGE_USE'] + + if myrepo is not None: + repos = [myrepo] + else: + # We iterate over self.porttrees, since it's common to + # tweak this attribute in order to adjust match behavior. + repos = [] + for tree in reversed(self.porttrees): + repos.append(self.repositories.get_name_for_location(tree)) + + for mycpv in cpv_iter: + for repo in repos: + metadata.clear() try: - if self.settings._getMissingLicenses(mycpv, metadata): - continue - if self.settings._getMissingProperties(mycpv, metadata): - continue - except InvalidDependString: + metadata.update(zip(aux_keys, + self.aux_get(mycpv, aux_keys, myrepo=repo))) + except KeyError: + continue + except PortageException as e: + writemsg("!!! Error: aux_get('%s', %s)\n" % + (mycpv, aux_keys), noiselevel=-1) + writemsg("!!! %s\n" % (e,), noiselevel=-1) + del e continue - newlist.append(mycpv) - return newlist + + if not self._visible(mycpv, metadata): + continue + + yield mycpv + # only yield a given cpv once + break + + def _visible(self, cpv, metadata): + eapi = metadata["EAPI"] + if not eapi_is_supported(eapi): + return False + if _eapi_is_deprecated(eapi): + return False + if not metadata["SLOT"]: + return False + + settings = self.settings + if settings._getMaskAtom(cpv, metadata): + return False + if settings._getMissingKeywords(cpv, metadata): + return False + if settings.local_config: + metadata['CHOST'] = settings.get('CHOST', '') + if not settings._accept_chost(cpv, metadata): + return False + metadata["USE"] = "" + if "?" in metadata["LICENSE"] or \ + "?" in metadata["PROPERTIES"]: + self.doebuild_settings.setcpv(cpv, mydb=metadata) + metadata['USE'] = self.doebuild_settings['PORTAGE_USE'] + try: + if settings._getMissingLicenses(cpv, metadata): + return False + if settings._getMissingProperties(cpv, metadata): + return False + except InvalidDependString: + return False + + return True def close_portdbapi_caches(): for i in portdbapi.portdbapi_instances: @@ -1011,7 +971,7 @@ def close_portdbapi_caches(): portage.process.atexit_register(portage.portageexit) class portagetree(object): - def __init__(self, root=None, virtual=None, settings=None): + def __init__(self, root=None, virtual=DeprecationWarning, settings=None): """ Constructor for a PortageTree @@ -1034,8 +994,14 @@ class portagetree(object): "settings['ROOT'] instead.", DeprecationWarning, stacklevel=2) + if virtual is not DeprecationWarning: + warnings.warn("The 'virtual' parameter of the " + "portage.dbapi.porttree.portagetree" + " constructor is unused", + DeprecationWarning, stacklevel=2) + self.portroot = settings["PORTDIR"] - self.virtual = virtual + self.__virtual = virtual self.dbapi = portdbapi(mysettings=settings) @property @@ -1044,9 +1010,17 @@ class portagetree(object): "portage.dbapi.porttree.portagetree" + \ " is deprecated. Use " + \ "settings['ROOT'] instead.", - DeprecationWarning, stacklevel=2) + DeprecationWarning, stacklevel=3) return self.settings['ROOT'] + @property + def virtual(self): + warnings.warn("The 'virtual' attribute of " + \ + "portage.dbapi.porttree.portagetree" + \ + " is deprecated.", + DeprecationWarning, stacklevel=3) + return self.__virtual + def dep_bestmatch(self,mydep): "compatibility method" mymatch = self.dbapi.xmatch("bestmatch-visible",mydep) @@ -1077,17 +1051,14 @@ class portagetree(object): psplit = pkgsplit(mysplit[1]) return "/".join([self.portroot, mysplit[0], psplit[0], mysplit[1]])+".ebuild" - def depcheck(self, mycheck, use="yes", myusesplit=None): - return dep_check(mycheck, self.dbapi, use=use, myuse=myusesplit) - def getslot(self,mycatpkg): "Get a slot for a catpkg; assume it exists." myslot = "" try: myslot = self.dbapi.aux_get(mycatpkg, ["SLOT"])[0] - except SystemExit as e: + except SystemExit: raise - except Exception as e: + except Exception: pass return myslot @@ -1148,7 +1119,7 @@ def _parse_uri_map(cpv, metadata, use=None): while myuris: uri = myuris.pop() if myuris and myuris[-1] == "->": - operator = myuris.pop() + myuris.pop() distfile = myuris.pop() else: distfile = os.path.basename(uri) @@ -1163,6 +1134,5 @@ def _parse_uri_map(cpv, metadata, use=None): uri_map[distfile] = uri_set uri_set.add(uri) uri = None - operator = None return uri_map |