def _aux_get_return(self, future, mycpv, mylist, myebuild, ebuild_hash, mydata, mylocation, cache_me, proc): if future.cancelled(): return if proc is not None: if proc.returncode != os.EX_OK: self._broken_ebuilds.add(myebuild) future.set_exception(PortageKeyError(mycpv)) return mydata = proc.metadata mydata["repository"] = self.repositories.get_name_for_location(mylocation) mydata["_mtime_"] = ebuild_hash.mtime eapi = mydata.get("EAPI") if not eapi: eapi = "0" mydata["EAPI"] = eapi 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] if cache_me and self.frozen: aux_cache = {} for x in self._aux_cache_keys: aux_cache[x] = mydata.get(x, "") self._aux_cache[mycpv] = aux_cache future.set_result(returnme)
def _pull_valid_cache(self, cpv, ebuild_path, repo_path): try: 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) raise PortageKeyError(cpv) # Pull pre-generated metadata from the metadata/cache/ # directory if it exists and is valid, otherwise fall # back to the normal writable cache. auxdbs = [] 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.repositories.get_repo_for_location( repo_path).eclass_db for auxdb in auxdbs: try: metadata = auxdb[cpv] except KeyError: continue except CacheError: if not auxdb.readonly: try: del auxdb[cpv] except (KeyError, CacheError): pass 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 else: metadata = None return (metadata, ebuild_hash)
def async_aux_get(self, mycpv, mylist, mytree=None, myrepo=None, loop=None): """ Asynchronous form form of aux_get. @param mycpv: cpv for an ebuild @type mycpv: str @param mylist: list of metadata keys @type mylist: list @param mytree: The canonical path of the tree in which the ebuild is located, or None for automatic lookup @type mytree: str @param myrepo: name of the repo in which the ebuild is located, or None for automatic lookup @type myrepo: str @param loop: event loop (defaults to global event loop) @type loop: EventLoop @return: list of metadata values @rtype: asyncio.Future (or compatible) """ # Don't default to self._event_loop here, since that creates a # local event loop for thread safety, and that could easily lead # to simultaneous instantiation of multiple event loops here. # Callers of this method certainly want the same event loop to # be used for all calls. loop = asyncio._wrap_loop(loop) future = loop.create_future() cache_me = False if myrepo is not None: mytree = self.treemap.get(myrepo) if mytree is None: future.set_exception(PortageKeyError(myrepo)) return future 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 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: future.set_result([aux_cache.get(x, "") for x in mylist]) return future cache_me = True try: cat, pkg = mycpv.split("/", 1) except ValueError: # Missing slash. Can't find ebuild so raise PortageKeyError. future.set_exception(PortageKeyError(mycpv)) return future myebuild, mylocation = self.findname2(mycpv, mytree) if not myebuild: writemsg("!!! aux_get(): %s\n" % \ _("ebuild not found for '%s'") % mycpv, noiselevel=1) future.set_exception(PortageKeyError(mycpv)) return future mydata, ebuild_hash = self._pull_valid_cache(mycpv, myebuild, mylocation) if mydata is not None: self._aux_get_return( future, mycpv, mylist, myebuild, ebuild_hash, mydata, mylocation, cache_me, None) return future if myebuild in self._broken_ebuilds: future.set_exception(PortageKeyError(mycpv)) return future proc = EbuildMetadataPhase(cpv=mycpv, ebuild_hash=ebuild_hash, portdb=self, repo_path=mylocation, scheduler=loop, settings=self.doebuild_settings) proc.addExitListener(functools.partial(self._aux_get_return, future, mycpv, mylist, myebuild, ebuild_hash, mydata, mylocation, cache_me)) future.add_done_callback(functools.partial(self._aux_get_cancel, proc)) proc.start() return future
def aux_get(self, mycpv, mylist, mytree=None, myrepo=None): "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc." 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]' 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or raise PortageKeyError if error' cache_me = False if myrepo is not None: mytree = self.treemap.get(myrepo) if mytree is None: raise PortageKeyError(myrepo) 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 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 try: cat, pkg = mycpv.split("/", 1) except ValueError: # Missing slash. Can't find ebuild so raise PortageKeyError. raise PortageKeyError(mycpv) myebuild, mylocation = self.findname2(mycpv, mytree) if not myebuild: writemsg("!!! aux_get(): %s\n" % \ _("ebuild not found for '%s'") % mycpv, noiselevel=1) raise PortageKeyError(mycpv) mydata, ebuild_hash = self._pull_valid_cache(mycpv, myebuild, mylocation) doregen = mydata is None if doregen: if myebuild in self._broken_ebuilds: raise PortageKeyError(mycpv) proc = EbuildMetadataPhase(cpv=mycpv, ebuild_hash=ebuild_hash, portdb=self, repo_path=mylocation, scheduler=self._event_loop, settings=self.doebuild_settings) proc.start() proc.wait() if proc.returncode != os.EX_OK: self._broken_ebuilds.add(myebuild) raise PortageKeyError(mycpv) mydata = proc.metadata mydata["repository"] = self.repositories.get_name_for_location(mylocation) mydata["_mtime_"] = ebuild_hash.mtime eapi = mydata.get("EAPI") if not eapi: eapi = "0" mydata["EAPI"] = eapi 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] if cache_me and self.frozen: aux_cache = {} for x in self._aux_cache_keys: aux_cache[x] = mydata.get(x, "") self._aux_cache[mycpv] = aux_cache return returnme