1 # Copyright 1998-2012 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
5 "close_portdbapi_caches", "FetchlistDict", "portagetree", "portdbapi"
9 portage.proxy.lazyimport.lazyimport(globals(),
11 'portage.data:portage_gid,secpass',
12 'portage.dbapi.dep_expand:dep_expand',
13 'portage.dep:Atom,dep_getkey,match_from_list,use_reduce,_match_slot',
14 'portage.package.ebuild.doebuild:doebuild',
15 'portage.util:ensure_dirs,shlex_split,writemsg,writemsg_level',
16 'portage.util.listdir:listdir',
17 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp,_pkg_str',
20 from portage.cache import volatile
21 from portage.cache.cache_errors import CacheError
22 from portage.cache.mappings import Mapping
23 from portage.dbapi import dbapi
24 from portage.exception import PortageException, \
25 FileNotFound, InvalidAtom, InvalidData, \
26 InvalidDependString, InvalidPackageName
27 from portage.localization import _
29 from portage import eclass_cache, \
32 from portage import os
33 from portage import _encodings
34 from portage import _unicode_encode
35 from portage import OrderedDict
36 from portage.util._eventloop.EventLoop import EventLoop
37 from _emerge.EbuildMetadataPhase import EbuildMetadataPhase
44 if sys.hexversion >= 0x3000000:
48 class portdbapi(dbapi):
49 """this tree will scan a portage directory located at root (passed to init)"""
50 portdbapi_instances = []
54 def _categories(self):
55 return self.settings.categories
58 def porttree_root(self):
59 return self.settings.repositories.mainRepoLocation()
63 main_repo = self.repositories.mainRepo()
66 return main_repo.eclass_db
68 def __init__(self, _unused_param=None, mysettings=None):
70 @param _unused_param: deprecated, use mysettings['PORTDIR'] instead
71 @type _unused_param: None
72 @param mysettings: an immutable config instance
73 @type mysettings: portage.config
75 portdbapi.portdbapi_instances.append(self)
77 from portage import config
79 self.settings = mysettings
81 from portage import settings
82 self.settings = config(clone=settings)
84 if _unused_param is not None:
85 warnings.warn("The first parameter of the " + \
86 "portage.dbapi.porttree.portdbapi" + \
87 " constructor is unused since portage-2.1.8. " + \
88 "mysettings['PORTDIR'] is used instead.",
89 DeprecationWarning, stacklevel=2)
91 self.repositories = self.settings.repositories
92 self.treemap = self.repositories.treemap
94 # This is strictly for use in aux_get() doebuild calls when metadata
95 # is generated by the depend phase. It's safest to use a clone for
96 # this purpose because doebuild makes many changes to the config
97 # instance that is passed in.
98 self.doebuild_settings = config(clone=self.settings)
99 self._event_loop = EventLoop(main=False)
100 self.depcachedir = os.path.realpath(self.settings.depcachedir)
102 if os.environ.get("SANDBOX_ON") == "1":
103 # Make api consumers exempt from sandbox violations
104 # when doing metadata cache updates.
105 sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
106 if self.depcachedir not in sandbox_write:
107 sandbox_write.append(self.depcachedir)
108 os.environ["SANDBOX_WRITE"] = \
109 ":".join(filter(None, sandbox_write))
111 self.porttrees = list(self.settings.repositories.repoLocationList())
113 # This is used as sanity check for aux_get(). If there is no
114 # root eclass dir, we assume that PORTDIR is invalid or
115 # missing. This check allows aux_get() to detect a missing
116 # portage tree and return early by raising a KeyError.
117 self._have_root_eclass_dir = os.path.isdir(
118 os.path.join(self.settings.repositories.mainRepoLocation(), "eclass"))
120 #if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening)
124 #Keep a list of repo names, sorted by priority (highest priority first).
125 self._ordered_repo_name_list = tuple(reversed(self.repositories.prepos_order))
127 self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule")
129 self._pregen_auxdb = {}
130 # If the current user doesn't have depcachedir write permission,
131 # then the depcachedir cache is kept here read-only access.
133 self._init_cache_dirs()
135 depcachedir_st = os.stat(self.depcachedir)
136 depcachedir_w_ok = os.access(self.depcachedir, os.W_OK)
138 depcachedir_st = None
139 depcachedir_w_ok = False
143 depcachedir_unshared = False
144 if portage.data.secpass < 1 and \
145 depcachedir_w_ok and \
146 depcachedir_st is not None and \
147 os.getuid() == depcachedir_st.st_uid and \
148 os.getgid() == depcachedir_st.st_gid:
149 # If this user owns depcachedir and is not in the
150 # portage group, then don't bother to set permissions
151 # on cache entries. This makes it possible to run
152 # egencache without any need to be a member of the
154 depcachedir_unshared = True
156 cache_kwargs.update({
161 # If secpass < 1, we don't want to write to the cache
162 # since then we won't be able to apply group permissions
163 # to the cache entries/directories.
164 if (secpass < 1 and not depcachedir_unshared) or not depcachedir_w_ok:
165 for x in self.porttrees:
166 self.auxdb[x] = volatile.database(
167 self.depcachedir, x, self._known_keys,
170 self._ro_auxdb[x] = self.auxdbmodule(self.depcachedir, x,
171 self._known_keys, readonly=True, **cache_kwargs)
175 for x in self.porttrees:
178 # location, label, auxdbkeys
179 self.auxdb[x] = self.auxdbmodule(
180 self.depcachedir, x, self._known_keys, **cache_kwargs)
181 if "metadata-transfer" not in self.settings.features:
182 for x in self.porttrees:
183 if x in self._pregen_auxdb:
185 cache = self._create_pregen_cache(x)
186 if cache is not None:
187 self._pregen_auxdb[x] = cache
188 # Selectively cache metadata in order to optimize dep matching.
189 self._aux_cache_keys = set(
190 ["DEPEND", "EAPI", "HDEPEND",
191 "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
192 "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", "repository",
193 "RESTRICT", "SLOT", "DEFINED_PHASES", "REQUIRED_USE"])
196 self._broken_ebuilds = set()
198 def _create_pregen_cache(self, tree):
199 conf = self.repositories.get_repo_for_location(tree)
200 cache = conf.get_pregenerated_cache(
201 self._known_keys, readonly=True)
202 if cache is not None:
204 cache.ec = self.repositories.get_repo_for_location(tree).eclass_db
205 except AttributeError:
208 if not cache.complete_eclass_entries:
210 ("Repository '%s' used deprecated 'pms' cache format. "
211 "Please migrate to 'md5-dict' format.") % (conf.name,),
216 def _init_cache_dirs(self):
217 """Create /var/cache/edb/dep and adjust permissions for the portage
224 ensure_dirs(self.depcachedir, gid=portage_gid,
225 mode=dirmode, mask=modemask)
226 except PortageException:
229 def close_caches(self):
230 if not hasattr(self, "auxdb"):
231 # unhandled exception thrown from constructor
237 def flush_cache(self):
238 for x in self.auxdb.values():
241 def findLicensePath(self, license_name):
242 for x in reversed(self.porttrees):
243 license_path = os.path.join(x, "licenses", license_name)
244 if os.access(license_path, os.R_OK):
248 def findname(self,mycpv, mytree = None, myrepo = None):
249 return self.findname2(mycpv, mytree, myrepo)[0]
251 def getRepositoryPath(self, repository_id):
253 This function is required for GLEP 42 compliance; given a valid repository ID
254 it must return a path to the repository
255 TreeMap = { id:path }
257 return self.treemap.get(repository_id)
259 def getRepositoryName(self, canonical_repo_path):
261 This is the inverse of getRepositoryPath().
262 @param canonical_repo_path: the canonical path of a repository, as
263 resolved by os.path.realpath()
264 @type canonical_repo_path: String
265 @return: The repo_name for the corresponding repository, or None
266 if the path does not correspond a known repository
267 @rtype: String or None
270 return self.repositories.get_name_for_location(canonical_repo_path)
274 def getRepositories(self):
276 This function is required for GLEP 42 compliance; it will return a list of
280 return self._ordered_repo_name_list
282 def getMissingRepoNames(self):
284 Returns a list of repository paths that lack profiles/repo_name.
286 return self.settings.repositories.missing_repo_names
288 def getIgnoredRepos(self):
290 Returns a list of repository paths that have been ignored, because
291 another repo with the same name exists.
293 return self.settings.repositories.ignored_repos
295 def findname2(self, mycpv, mytree=None, myrepo = None):
297 Returns the location of the CPV, and what overlay it was in.
298 Searches overlays first, then PORTDIR; this allows us to return the first
299 matching file. As opposed to starting in portdir and then doing overlays
300 second, we would have to exhaustively search the overlays until we found
302 If myrepo is not None it will find packages from this repository(overlay)
307 if myrepo is not None:
308 mytree = self.treemap.get(myrepo)
312 mysplit = mycpv.split("/")
313 psplit = pkgsplit(mysplit[1])
314 if psplit is None or len(mysplit) != 2:
315 raise InvalidPackageName(mycpv)
317 # For optimal performace in this hot spot, we do manual unicode
318 # handling here instead of using the wrapped os module.
319 encoding = _encodings['fs']
325 mytrees = reversed(self.porttrees)
327 relative_path = mysplit[0] + _os.sep + psplit[0] + _os.sep + \
328 mysplit[1] + ".ebuild"
331 filename = x + _os.sep + relative_path
332 if _os.access(_unicode_encode(filename,
333 encoding=encoding, errors=errors), _os.R_OK):
337 def _write_cache(self, cpv, repo_path, metadata, ebuild_hash):
340 cache = self.auxdb[repo_path]
341 chf = cache.validation_chf
342 metadata['_%s_' % chf] = getattr(ebuild_hash, chf)
344 # Normally this shouldn't happen, so we'll show
345 # a traceback for debugging purposes.
346 traceback.print_exc()
349 if cache is not None:
351 cache[cpv] = metadata
353 # Normally this shouldn't happen, so we'll show
354 # a traceback for debugging purposes.
355 traceback.print_exc()
357 def _pull_valid_cache(self, cpv, ebuild_path, repo_path):
359 ebuild_hash = eclass_cache.hashed_path(ebuild_path)
360 # snag mtime since we use it later, and to trigger stat failure
361 # if it doesn't exist
364 writemsg(_("!!! aux_get(): ebuild for " \
365 "'%s' does not exist at:\n") % (cpv,), noiselevel=-1)
366 writemsg("!!! %s\n" % ebuild_path, noiselevel=-1)
369 # Pull pre-generated metadata from the metadata/cache/
370 # directory if it exists and is valid, otherwise fall
371 # back to the normal writable cache.
373 pregen_auxdb = self._pregen_auxdb.get(repo_path)
374 if pregen_auxdb is not None:
375 auxdbs.append(pregen_auxdb)
376 ro_auxdb = self._ro_auxdb.get(repo_path)
377 if ro_auxdb is not None:
378 auxdbs.append(ro_auxdb)
379 auxdbs.append(self.auxdb[repo_path])
380 eclass_db = self.repositories.get_repo_for_location(repo_path).eclass_db
384 metadata = auxdb[cpv]
388 if not auxdb.readonly:
391 except (KeyError, CacheError):
394 eapi = metadata.get('EAPI', '').strip()
397 metadata['EAPI'] = eapi
398 if not eapi_is_supported(eapi):
399 # Since we're supposed to be able to efficiently obtain the
400 # EAPI from _parse_eapi_ebuild_head, we disregard cache entries
401 # for unsupported EAPIs.
403 if auxdb.validate_entry(metadata, ebuild_hash, eclass_db):
408 return (metadata, ebuild_hash)
410 def aux_get(self, mycpv, mylist, mytree=None, myrepo=None):
411 "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc."
412 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]'
413 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or raise KeyError if error'
415 if myrepo is not None:
416 mytree = self.treemap.get(myrepo)
418 raise KeyError(myrepo)
420 if mytree is not None and len(self.porttrees) == 1 \
421 and mytree == self.porttrees[0]:
422 # mytree matches our only tree, so it's safe to
423 # ignore mytree and cache the result
429 if mytree is None and not self._known_keys.intersection(
430 mylist).difference(self._aux_cache_keys):
431 aux_cache = self._aux_cache.get(mycpv)
432 if aux_cache is not None:
433 return [aux_cache.get(x, "") for x in mylist]
437 cat, pkg = mycpv.split("/", 1)
439 # Missing slash. Can't find ebuild so raise KeyError.
440 raise KeyError(mycpv)
442 myebuild, mylocation = self.findname2(mycpv, mytree)
445 writemsg("!!! aux_get(): %s\n" % \
446 _("ebuild not found for '%s'") % mycpv, noiselevel=1)
447 raise KeyError(mycpv)
449 mydata, ebuild_hash = self._pull_valid_cache(mycpv, myebuild, mylocation)
450 doregen = mydata is None
453 if myebuild in self._broken_ebuilds:
454 raise KeyError(mycpv)
456 proc = EbuildMetadataPhase(cpv=mycpv,
457 ebuild_hash=ebuild_hash, portdb=self,
458 repo_path=mylocation, scheduler=self._event_loop,
459 settings=self.doebuild_settings)
464 if proc.returncode != os.EX_OK:
465 self._broken_ebuilds.add(myebuild)
466 raise KeyError(mycpv)
468 mydata = proc.metadata
470 mydata["repository"] = self.repositories.get_name_for_location(mylocation)
471 mydata["_mtime_"] = ebuild_hash.mtime
472 eapi = mydata.get("EAPI")
475 mydata["EAPI"] = eapi
476 if eapi_is_supported(eapi):
477 mydata["INHERITED"] = " ".join(mydata.get("_eclasses_", []))
479 #finally, we look at our internal cache entry and return the requested data.
480 returnme = [mydata.get(x, "") for x in mylist]
484 for x in self._aux_cache_keys:
485 aux_cache[x] = mydata.get(x, "")
486 self._aux_cache[mycpv] = aux_cache
490 def getFetchMap(self, mypkg, useflags=None, mytree=None):
492 Get the SRC_URI metadata as a dict which maps each file name to a
493 set of alternative URIs.
495 @param mypkg: cpv for an ebuild
497 @param useflags: a collection of enabled USE flags, for evaluation of
499 @type useflags: set, or None to enable all conditionals
500 @param mytree: The canonical path of the tree in which the ebuild
501 is located, or None for automatic lookup
503 @return: A dict which maps each file name to a set of alternative
509 eapi, myuris = self.aux_get(mypkg,
510 ["EAPI", "SRC_URI"], mytree=mytree)
512 # Convert this to an InvalidDependString exception since callers
514 raise portage.exception.InvalidDependString(
515 "getFetchMap(): aux_get() error reading "+mypkg+"; aborting.")
517 if not eapi_is_supported(eapi):
518 # Convert this to an InvalidDependString exception
519 # since callers already handle it.
520 raise portage.exception.InvalidDependString(
521 "getFetchMap(): '%s' has unsupported EAPI: '%s'" % \
524 return _parse_uri_map(mypkg, {'EAPI':eapi,'SRC_URI':myuris},
527 def getfetchsizes(self, mypkg, useflags=None, debug=0, myrepo=None):
528 # returns a filename:size dictionnary of remaining downloads
529 myebuild, mytree = self.findname2(mypkg, myrepo=myrepo)
531 raise AssertionError(_("ebuild not found for '%s'") % mypkg)
532 pkgdir = os.path.dirname(myebuild)
533 mf = self.repositories.get_repo_for_location(
534 os.path.dirname(os.path.dirname(pkgdir))).load_manifest(
535 pkgdir, self.settings["DISTDIR"])
536 checksums = mf.getDigests()
539 writemsg(_("[empty/missing/bad digest]: %s\n") % (mypkg,))
542 myfiles = self.getFetchMap(mypkg, useflags=useflags, mytree=mytree)
543 #XXX: maybe this should be improved: take partial downloads
544 # into account? check checksums?
545 for myfile in myfiles:
547 fetch_size = int(checksums[myfile]["size"])
548 except (KeyError, ValueError):
550 writemsg(_("[bad digest]: missing %(file)s for %(pkg)s\n") % {"file":myfile, "pkg":mypkg})
552 file_path = os.path.join(self.settings["DISTDIR"], myfile)
555 mystat = os.stat(file_path)
560 ro_distdirs = self.settings.get("PORTAGE_RO_DISTDIRS")
561 if ro_distdirs is not None:
562 for x in shlex_split(ro_distdirs):
564 mystat = os.stat(os.path.join(x, myfile))
568 if mystat.st_size == fetch_size:
569 existing_size = fetch_size
572 existing_size = mystat.st_size
573 remaining_size = fetch_size - existing_size
574 if remaining_size > 0:
575 # Assume the download is resumable.
576 filesdict[myfile] = remaining_size
577 elif remaining_size < 0:
578 # The existing file is too large and therefore corrupt.
579 filesdict[myfile] = int(checksums[myfile]["size"])
582 def fetch_check(self, mypkg, useflags=None, mysettings=None, all=False, myrepo=None):
584 TODO: account for PORTAGE_RO_DISTDIRS
588 elif useflags is None:
590 useflags = mysettings["USE"].split()
591 if myrepo is not None:
592 mytree = self.treemap.get(myrepo)
598 myfiles = self.getFetchMap(mypkg, useflags=useflags, mytree=mytree)
599 myebuild = self.findname(mypkg, myrepo=myrepo)
601 raise AssertionError(_("ebuild not found for '%s'") % mypkg)
602 pkgdir = os.path.dirname(myebuild)
603 mf = self.repositories.get_repo_for_location(
604 os.path.dirname(os.path.dirname(pkgdir)))
605 mf = mf.load_manifest(pkgdir, self.settings["DISTDIR"])
606 mysums = mf.getDigests()
610 if not mysums or x not in mysums:
612 reason = _("digest missing")
615 ok, reason = portage.checksum.verify_all(
616 os.path.join(self.settings["DISTDIR"], x), mysums[x])
617 except FileNotFound as e:
619 reason = _("File Not Found: '%s'") % (e,)
626 def cpv_exists(self, mykey, myrepo=None):
627 "Tells us whether an actual ebuild exists on disk (no masking)"
628 cps2 = mykey.split("/")
629 cps = catpkgsplit(mykey, silent=0)
633 if self.findname(cps[0] + "/" + cps2[1], myrepo=myrepo):
638 def cp_all(self, categories=None, trees=None):
640 This returns a list of all keys in our tree or trees
641 @param categories: optional list of categories to search or
642 defaults to self.settings.categories
643 @param trees: optional list of trees to search the categories in or
644 defaults to self.porttrees
645 @rtype list of [cat/pkg,...]
648 if categories is None:
649 categories = self.settings.categories
651 trees = self.porttrees
654 for y in listdir(oroot+"/"+x, EmptyOnError=1, ignorecvs=1, dirsonly=1):
656 atom = Atom("%s/%s" % (x, y))
666 def cp_list(self, mycp, use_cache=1, mytree=None):
667 # NOTE: Cache can be safely shared with the match cache, since the
668 # match cache uses the result from dep_expand for the cache_key.
669 if self.frozen and mytree is not None \
670 and len(self.porttrees) == 1 \
671 and mytree == self.porttrees[0]:
672 # mytree matches our only tree, so it's safe to
673 # ignore mytree and cache the result
676 if self.frozen and mytree is None:
677 cachelist = self.xcache["cp-list"].get(mycp)
678 if cachelist is not None:
679 # Try to propagate this to the match-all cache here for
680 # repoman since he uses separate match-all caches for each
681 # profile (due to differences in _get_implicit_iuse).
682 self.xcache["match-all"][(mycp, mycp)] = cachelist
684 mysplit = mycp.split("/")
685 invalid_category = mysplit[0] not in self._categories
687 if mytree is not None:
688 if isinstance(mytree, basestring):
691 # assume it's iterable
694 mytrees = self.porttrees
695 for oroot in mytrees:
697 file_list = os.listdir(os.path.join(oroot, mycp))
702 if x[-7:] == '.ebuild':
708 writemsg(_("\nInvalid ebuild name: %s\n") % \
709 os.path.join(oroot, mycp, x), noiselevel=-1)
711 if ps[0] != mysplit[1]:
712 writemsg(_("\nInvalid ebuild name: %s\n") % \
713 os.path.join(oroot, mycp, x), noiselevel=-1)
715 ver_match = ver_regexp.match("-".join(ps[1:]))
716 if ver_match is None or not ver_match.groups():
717 writemsg(_("\nInvalid ebuild version: %s\n") % \
718 os.path.join(oroot, mycp, x), noiselevel=-1)
720 d[_pkg_str(mysplit[0]+"/"+pf)] = None
721 if invalid_category and d:
722 writemsg(_("\n!!! '%s' has a category that is not listed in " \
723 "%setc/portage/categories\n") % \
724 (mycp, self.settings["PORTAGE_CONFIGROOT"]), noiselevel=-1)
728 # Always sort in ascending order here since it's handy
729 # and the result can be easily cached and reused.
730 self._cpv_sort_ascending(mylist)
731 if self.frozen and mytree is None:
732 cachelist = mylist[:]
733 self.xcache["cp-list"][mycp] = cachelist
734 self.xcache["match-all"][(mycp, mycp)] = cachelist
738 for x in "bestmatch-visible", "cp-list", "match-all", \
739 "match-all-cpv-only", "match-visible", "minimum-all", \
748 def xmatch(self,level,origdep,mydep=None,mykey=None,mylist=None):
749 "caching match function; very trick stuff"
750 if level == "list-visible":
751 level = "match-visible"
752 warnings.warn("The 'list-visible' mode of "
753 "portage.dbapi.porttree.portdbapi.xmatch "
754 "has been renamed to match-visible",
755 DeprecationWarning, stacklevel=2)
758 #this stuff only runs on first call of xmatch()
759 #create mydep, mykey from origdep
760 mydep = dep_expand(origdep, mydb=self, settings=self.settings)
763 #if no updates are being made to the tree, we can consult our xcache...
766 cache_key = (mydep, mydep.unevaluated_atom)
768 return self.xcache[level][cache_key][:]
774 if mydep.repo is not None:
775 mytree = self.treemap.get(mydep.repo)
777 if level.startswith("match-"):
782 if myval is not None:
783 # Unknown repo, empty result.
785 elif level == "match-all-cpv-only":
786 # match *all* packages, only against the cpv, in order
787 # to bypass unnecessary cache access for things like IUSE
790 # Share cache with match-all/cp_list when the result is the
791 # same. Note that this requires that mydep.repo is None and
792 # thus mytree is also None.
794 myval = self.cp_list(mykey, mytree=mytree)
796 myval = match_from_list(mydep,
797 self.cp_list(mykey, mytree=mytree))
799 elif level in ("bestmatch-visible", "match-all", "match-visible",
800 "minimum-all", "minimum-visible"):
801 # Find the minimum matching visible version. This is optimized to
802 # minimize the number of metadata accesses (improves performance
803 # especially in cases where metadata needs to be generated).
805 mylist = self.cp_list(mykey, mytree=mytree)
807 mylist = match_from_list(mydep,
808 self.cp_list(mykey, mytree=mytree))
810 visibility_filter = level not in ("match-all", "minimum-all")
811 single_match = level not in ("match-all", "match-visible")
813 aux_keys = list(self._aux_cache_keys)
814 if level == "bestmatch-visible":
819 if mydep.repo is not None:
822 # We iterate over self.porttrees, since it's common to
823 # tweak this attribute in order to adjust match behavior.
825 for tree in reversed(self.porttrees):
826 repos.append(self.repositories.get_name_for_location(tree))
828 for cpv in iterfunc(mylist):
831 metadata = dict(zip(aux_keys,
832 self.aux_get(cpv, aux_keys, myrepo=repo)))
834 # ebuild not in this repo, or masked by corruption
838 pkg_str = _pkg_str(cpv, metadata=metadata,
839 settings=self.settings)
843 if visibility_filter and not self._visible(pkg_str, metadata):
846 if mydep.slot is not None and \
847 not _match_slot(mydep, pkg_str):
850 if mydep.unevaluated_atom.use is not None and \
851 not self._match_use(mydep, pkg_str, metadata):
854 myval.append(pkg_str)
855 # only yield a given cpv once
858 if myval and single_match:
867 elif level == "bestmatch-list":
868 #dep match -- find best match but restrict search to sublist
869 warnings.warn("The 'bestmatch-list' mode of "
870 "portage.dbapi.porttree.portdbapi.xmatch is deprecated",
871 DeprecationWarning, stacklevel=2)
872 myval = best(list(self._iter_match(mydep, mylist)))
873 elif level == "match-list":
874 #dep match -- find all matches but restrict search to sublist (used in 2nd half of visible())
875 warnings.warn("The 'match-list' mode of "
876 "portage.dbapi.porttree.portdbapi.xmatch is deprecated",
877 DeprecationWarning, stacklevel=2)
878 myval = list(self._iter_match(mydep, mylist))
880 raise AssertionError(
881 "Invalid level argument: '%s'" % level)
884 xcache_this_level = self.xcache.get(level)
885 if xcache_this_level is not None:
886 xcache_this_level[cache_key] = myval
887 if not isinstance(myval, _pkg_str):
892 def match(self, mydep, use_cache=1):
893 return self.xmatch("match-visible", mydep)
895 def gvisible(self, mylist):
896 warnings.warn("The 'gvisible' method of "
897 "portage.dbapi.porttree.portdbapi "
899 DeprecationWarning, stacklevel=2)
900 return list(self._iter_visible(iter(mylist)))
902 def visible(self, cpv_iter):
903 warnings.warn("The 'visible' method of "
904 "portage.dbapi.porttree.portdbapi "
906 DeprecationWarning, stacklevel=2)
909 return list(self._iter_visible(iter(cpv_iter)))
911 def _iter_visible(self, cpv_iter, myrepo=None):
913 Return a new list containing only visible packages.
915 aux_keys = list(self._aux_cache_keys)
918 if myrepo is not None:
921 # We iterate over self.porttrees, since it's common to
922 # tweak this attribute in order to adjust match behavior.
924 for tree in reversed(self.porttrees):
925 repos.append(self.repositories.get_name_for_location(tree))
927 for mycpv in cpv_iter:
931 metadata.update(zip(aux_keys,
932 self.aux_get(mycpv, aux_keys, myrepo=repo)))
935 except PortageException as e:
936 writemsg("!!! Error: aux_get('%s', %s)\n" %
937 (mycpv, aux_keys), noiselevel=-1)
938 writemsg("!!! %s\n" % (e,), noiselevel=-1)
942 if not self._visible(mycpv, metadata):
946 # only yield a given cpv once
949 def _visible(self, cpv, metadata):
950 eapi = metadata["EAPI"]
951 if not eapi_is_supported(eapi):
953 if _eapi_is_deprecated(eapi):
955 if not metadata["SLOT"]:
958 settings = self.settings
959 if settings._getMaskAtom(cpv, metadata):
961 if settings._getMissingKeywords(cpv, metadata):
963 if settings.local_config:
964 metadata['CHOST'] = settings.get('CHOST', '')
965 if not settings._accept_chost(cpv, metadata):
968 if "?" in metadata["LICENSE"] or \
969 "?" in metadata["PROPERTIES"]:
970 self.doebuild_settings.setcpv(cpv, mydb=metadata)
971 metadata['USE'] = self.doebuild_settings['PORTAGE_USE']
973 if settings._getMissingLicenses(cpv, metadata):
975 if settings._getMissingProperties(cpv, metadata):
977 except InvalidDependString:
982 def close_portdbapi_caches():
983 for i in portdbapi.portdbapi_instances:
986 portage.process.atexit_register(portage.portageexit)
988 class portagetree(object):
989 def __init__(self, root=None, virtual=DeprecationWarning, settings=None):
991 Constructor for a PortageTree
993 @param root: deprecated, defaults to settings['ROOT']
994 @type root: String/Path
995 @param virtual: UNUSED
996 @type virtual: No Idea
997 @param settings: Portage Configuration object (portage.settings)
998 @type settings: Instance of portage.config
1001 if settings is None:
1002 settings = portage.settings
1003 self.settings = settings
1005 if root is not None and root != settings['ROOT']:
1006 warnings.warn("The root parameter of the " + \
1007 "portage.dbapi.porttree.portagetree" + \
1008 " constructor is now unused. Use " + \
1009 "settings['ROOT'] instead.",
1010 DeprecationWarning, stacklevel=2)
1012 if virtual is not DeprecationWarning:
1013 warnings.warn("The 'virtual' parameter of the "
1014 "portage.dbapi.porttree.portagetree"
1015 " constructor is unused",
1016 DeprecationWarning, stacklevel=2)
1018 self.portroot = settings["PORTDIR"]
1019 self.__virtual = virtual
1020 self.dbapi = portdbapi(mysettings=settings)
1024 warnings.warn("The root attribute of " + \
1025 "portage.dbapi.porttree.portagetree" + \
1026 " is deprecated. Use " + \
1027 "settings['ROOT'] instead.",
1028 DeprecationWarning, stacklevel=3)
1029 return self.settings['ROOT']
1033 warnings.warn("The 'virtual' attribute of " + \
1034 "portage.dbapi.porttree.portagetree" + \
1036 DeprecationWarning, stacklevel=3)
1037 return self.__virtual
1039 def dep_bestmatch(self,mydep):
1040 "compatibility method"
1041 mymatch = self.dbapi.xmatch("bestmatch-visible",mydep)
1046 def dep_match(self,mydep):
1047 "compatibility method"
1048 mymatch = self.dbapi.xmatch("match-visible",mydep)
1053 def exists_specific(self,cpv):
1054 return self.dbapi.cpv_exists(cpv)
1056 def getallnodes(self):
1057 """new behavior: these are all *unmasked* nodes. There may or may not be available
1058 masked package for nodes in this nodes list."""
1059 return self.dbapi.cp_all()
1061 def getname(self, pkgname):
1062 "returns file location for this particular package (DEPRECATED)"
1065 mysplit = pkgname.split("/")
1066 psplit = pkgsplit(mysplit[1])
1067 return "/".join([self.portroot, mysplit[0], psplit[0], mysplit[1]])+".ebuild"
1069 def getslot(self,mycatpkg):
1070 "Get a slot for a catpkg; assume it exists."
1073 myslot = self.dbapi._pkg_str(mycatpkg, None).slot
1078 class FetchlistDict(Mapping):
1080 This provide a mapping interface to retrieve fetch lists. It's used
1081 to allow portage.manifest.Manifest to access fetch lists via a standard
1082 mapping interface rather than use the dbapi directly.
1084 def __init__(self, pkgdir, settings, mydbapi):
1085 """pkgdir is a directory containing ebuilds and settings is passed into
1086 portdbapi.getfetchlist for __getitem__ calls."""
1087 self.pkgdir = pkgdir
1088 self.cp = os.sep.join(pkgdir.split(os.sep)[-2:])
1089 self.settings = settings
1090 self.mytree = os.path.realpath(os.path.dirname(os.path.dirname(pkgdir)))
1091 self.portdb = mydbapi
1093 def __getitem__(self, pkg_key):
1094 """Returns the complete fetch list for a given package."""
1095 return list(self.portdb.getFetchMap(pkg_key, mytree=self.mytree))
1097 def __contains__(self, cpv):
1098 return cpv in self.__iter__()
1100 def has_key(self, pkg_key):
1101 """Returns true if the given package exists within pkgdir."""
1102 warnings.warn("portage.dbapi.porttree.FetchlistDict.has_key() is "
1103 "deprecated, use the 'in' operator instead",
1104 DeprecationWarning, stacklevel=2)
1105 return pkg_key in self
1108 return iter(self.portdb.cp_list(self.cp, mytree=self.mytree))
1111 """This needs to be implemented in order to avoid
1112 infinite recursion in some cases."""
1113 return len(self.portdb.cp_list(self.cp, mytree=self.mytree))
1116 """Returns keys for all packages within pkgdir"""
1117 return self.portdb.cp_list(self.cp, mytree=self.mytree)
1119 if sys.hexversion >= 0x3000000:
1122 def _parse_uri_map(cpv, metadata, use=None):
1124 myuris = use_reduce(metadata.get('SRC_URI', ''),
1125 uselist=use, matchall=(use is None),
1127 eapi=metadata['EAPI'])
1129 uri_map = OrderedDict()
1134 if myuris and myuris[-1] == "->":
1136 distfile = myuris.pop()
1138 distfile = os.path.basename(uri)
1140 raise portage.exception.InvalidDependString(
1141 ("getFetchMap(): '%s' SRC_URI has no file " + \
1142 "name: '%s'") % (cpv, uri))
1144 uri_set = uri_map.get(distfile)
1146 # Use OrderedDict to preserve order from SRC_URI
1147 # while ensuring uniqueness.
1148 uri_set = OrderedDict()
1149 uri_map[distfile] = uri_set
1152 # Convert OrderedDicts to tuples.
1153 for k, v in uri_map.items():
1154 uri_map[k] = tuple(v)