def register(self, cpv, slot, counter, paths): """ Register new objects in the registry. If there is a record with the same packagename (internally derived from cpv) and slot it is overwritten with the new data. @param cpv: package instance that owns the objects @type cpv: CPV (as String) @param slot: the value of SLOT of the given package instance @type slot: String @param counter: vdb counter value for the package instance @type counter: String @param paths: absolute paths of objects that got preserved during an update @type paths: List """ cp = cpv_getkey(cpv) cps = cp + ":" + slot counter = self._normalize_counter(counter) if len(paths) == 0 and cps in self._data \ and self._data[cps][0] == cpv and \ self._normalize_counter(self._data[cps][1]) == counter: del self._data[cps] elif len(paths) > 0: if isinstance(paths, set): # convert set to list, for write with JSONEncoder paths = list(paths) self._data[cps] = (cpv, counter, paths)
def getUseForce(self, pkg=None): if pkg is None: return frozenset(stack_lists( self._useforce_list, incremental=True)) cp = getattr(pkg, "cp", None) if cp is None: cp = cpv_getkey(remove_slot(pkg)) useforce = [] if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO: repos = [] try: repos.extend(repo.name for repo in self.repositories[pkg.repo].masters) except KeyError: pass repos.append(pkg.repo) for repo in repos: useforce.append(self._repo_useforce_dict.get(repo, {})) cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp) if cpdict: pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) if pkg_useforce: useforce.extend(pkg_useforce) for i, puseforce_dict in enumerate(self._puseforce_list): if self._useforce_list[i]: useforce.append(self._useforce_list[i]) cpdict = puseforce_dict.get(cp) if cpdict: pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) if pkg_useforce: useforce.extend(pkg_useforce) return frozenset(stack_lists(useforce, incremental=True))
def _getMaskAtom(self, cpv, slot, repo, unmask_atoms=None): """ Take a package and return a matching package.mask atom, or None if no such atom exists or it has been cancelled by package.unmask. PROVIDE is not checked, so atoms will not be found for old-style virtuals. @param cpv: The package name @type cpv: String @param slot: The package's slot @type slot: String @param repo: The package's repository [optional] @type repo: String @param unmask_atoms: if desired pass in self._punmaskdict.get(cp) @type unmask_atoms: list @rtype: String @return: A matching atom string or None if one is not found. """ cp = cpv_getkey(cpv) mask_atoms = self._pmaskdict.get(cp) if mask_atoms: pkg = "".join((cpv, _slot_separator, slot)) if repo and repo != Package.UNKNOWN_REPO: pkg = "".join((pkg, _repo_separator, repo)) pkg_list = [pkg] for x in mask_atoms: if not match_from_list(x, pkg_list): continue if unmask_atoms: for y in unmask_atoms: if match_from_list(y, pkg_list): return None return x return None
def add_depgraph_virtuals(self, mycpv, virts): """This updates the preferences for old-style virtuals, affecting the behavior of dep_expand() and dep_check() calls. It can change dbapi.match() behavior since that calls dep_expand(). However, dbapi instances have internal match caches that are not invalidated when preferences are updated here. This can potentially lead to some inconsistency (relevant to bug #1343).""" #Ensure that self._virtuals is populated. if self._virtuals is None: self.getvirtuals() modified = False cp = Atom(cpv_getkey(mycpv)) for virt in virts: try: virt = Atom(virt).cp except InvalidAtom: continue providers = self._virtuals.get(virt) if providers and cp in providers: continue providers = self._depgraphVirtuals.get(virt) if providers is None: providers = [] self._depgraphVirtuals[virt] = providers if cp not in providers: providers.append(cp) modified = True if modified: self._compile_virtuals()
def getMaskAtom(self, cpv, slot): """ Take a package and return a matching package.mask atom, or None if no such atom exists or it has been cancelled by package.unmask. PROVIDE is not checked, so atoms will not be found for old-style virtuals. @param cpv: The package name @type cpv: String @param slot: The package's slot @type slot: String @rtype: String @return: An matching atom string or None if one is not found. """ cp = cpv_getkey(cpv) mask_atoms = self._pmaskdict.get(cp) if mask_atoms: pkg_list = ["%s:%s" % (cpv, slot)] unmask_atoms = self._punmaskdict.get(cp) for x in mask_atoms: if not match_from_list(x, pkg_list): continue if unmask_atoms: for y in unmask_atoms: if match_from_list(y, pkg_list): return None return x return None
def _instance_key_multi_instance(self, cpv, support_string=False): try: return (cpv, cpv.build_id, cpv.file_size, cpv.build_time, cpv.mtime) except AttributeError: if not support_string: raise # Fallback for interfaces such as aux_get where API consumers # may pass in a plain string. latest = None for pkg in self.cp_list(cpv_getkey(cpv)): if pkg == cpv and (latest is None or latest.build_time < pkg.build_time): latest = pkg if latest is not None: return ( latest, latest.build_id, latest.file_size, latest.build_time, latest.mtime, ) raise KeyError(cpv)
def applyDelta(self, data): packages = self._vardb._aux_cache["packages"] added_slots = {} for delta in data["deltas"]: cpv = delta["package"] + "-" + delta["version"] event = delta["event"] if event == "add": added_slots[cpv] = delta # Use aux_get to populate the cache # for this cpv. if cpv not in packages: try: self._vardb.aux_get(cpv, ["DESCRIPTION"]) except KeyError: pass elif event == "remove": packages.pop(cpv, None) # Remove replaced versions from updated slots for cached_cpv, (mtime, metadata) in list(packages.items()): if cached_cpv in added_slots: continue replaced = False for cpv, delta in added_slots.items(): if (cached_cpv.startswith(delta["package"]) and metadata.get("SLOT") == delta["slot"] and cpv_getkey(cached_cpv) == delta["package"]): replaced = True break if replaced: del packages[cached_cpv] del added_slots[cpv] if not added_slots: break
def iterAtomsForPackage(self, pkg): """ Find all matching atoms for a given package. This matches virtual arguments against the PROVIDE metadata. This will raise an InvalidDependString exception if PROVIDE is invalid. """ cpv_slot_list = [pkg] cp = cpv_getkey(pkg.cpv) self._load() # make sure the atoms are loaded atoms = self._atommap.get(cp) if atoms: for atom in atoms: if match_from_list(atom, cpv_slot_list): yield atom provides = pkg._metadata["PROVIDE"] if not provides: return provides = provides.split() for provide in provides: try: provided_cp = Atom(provide).cp except InvalidAtom: continue atoms = self._atommap.get(provided_cp) if atoms: for atom in atoms: if match_from_list(atom.replace(provided_cp, cp), cpv_slot_list): yield atom
def iterAtomsForPackage(self, pkg): """ Find all matching atoms for a given package. This matches virtual arguments against the PROVIDE metadata. This will raise an InvalidDependString exception if PROVIDE is invalid. """ cpv_slot_list = [pkg] cp = cpv_getkey(pkg.cpv) self._load() # make sure the atoms are loaded atoms = self._atommap.get(cp) if atoms: for atom in atoms: if match_from_list(atom, cpv_slot_list): yield atom provides = pkg._metadata['PROVIDE'] if not provides: return provides = provides.split() for provide in provides: try: provided_cp = Atom(provide).cp except InvalidAtom: continue atoms = self._atommap.get(provided_cp) if atoms: for atom in atoms: if match_from_list(atom.replace(provided_cp, cp), cpv_slot_list): yield atom
def register(self, cpv, slot, counter, paths): """ Register new objects in the registry. If there is a record with the same packagename (internally derived from cpv) and slot it is overwritten with the new data. @param cpv: package instance that owns the objects @type cpv: CPV (as String) @param slot: the value of SLOT of the given package instance @type slot: String @param counter: vdb counter value for the package instance @type counter: String @param paths: absolute paths of objects that got preserved during an update @type paths: List """ cp = cpv_getkey(cpv) cps = cp+":"+slot counter = self._normalize_counter(counter) if len(paths) == 0 and cps in self._data \ and self._data[cps][0] == cpv and \ self._normalize_counter(self._data[cps][1]) == counter: del self._data[cps] elif len(paths) > 0: if isinstance(paths, set): # convert set to list, for write with JSONEncoder paths = list(paths) self._data[cps] = (cpv, counter, paths)
def cpv_remove(self,mycpv): """Removes a cpv from the list of available packages.""" self._clear_cache() mycp = cpv_getkey(mycpv) if mycpv in self.cpvdict: del self.cpvdict[mycpv] if mycp not in self.cpdict: return while mycpv in self.cpdict[mycp]: del self.cpdict[mycp][self.cpdict[mycp].index(mycpv)] if not len(self.cpdict[mycp]): del self.cpdict[mycp]
def cpv_remove(self, mycpv): """Removes a cpv from the list of available packages.""" self._clear_cache() mycp = cpv_getkey(mycpv) if mycpv in self.cpvdict: del self.cpvdict[mycpv] if mycp not in self.cpdict: return while mycpv in self.cpdict[mycp]: del self.cpdict[mycp][self.cpdict[mycp].index(mycpv)] if not len(self.cpdict[mycp]): del self.cpdict[mycp]
def getKeywords(self, cpv, slot, keywords, repo): cp = cpv_getkey(cpv) pkg = "".join((cpv, _slot_separator, slot)) if repo and repo != Package.UNKNOWN_REPO: pkg = "".join((pkg, _repo_separator, repo)) keywords = [[x for x in keywords.split() if x != "-*"]] for pkeywords_dict in self._pkeywords_list: cpdict = pkeywords_dict.get(cp) if cpdict: pkg_keywords = ordered_by_atom_specificity(cpdict, pkg) if pkg_keywords: keywords.extend(pkg_keywords) return stack_lists(keywords, incremental=True)
def mapPathsToAtoms(self, paths): rValue = set() for p in paths: for cpv in self.dbapi._linkmap.getOwners(p): try: slot, = self.dbapi.aux_get(cpv, ["SLOT"]) except KeyError: # This is expected for preserved libraries # of packages that have been uninstalled # without replacement. pass else: rValue.add("%s:%s" % (cpv_getkey(cpv), slot)) return rValue
def getPUSE(self, pkg): cp = getattr(pkg, "cp", None) if cp is None: cp = cpv_getkey(remove_slot(pkg)) ret = "" cpdict = self._pusedict.get(cp) if cpdict: puse_matches = ordered_by_atom_specificity(cpdict, pkg) if puse_matches: puse_list = [] for x in puse_matches: puse_list.extend(x) ret = " ".join(puse_list) return ret
def cpv_remove(self,mycpv): """Removes a cpv from the list of available packages.""" self._clear_cache() mycp = cpv_getkey(mycpv) instance_key = self._instance_key(mycpv) self.cpvdict.pop(instance_key, None) cp_list = self.cpdict.get(mycp) if cp_list is not None: cp_list = [x for x in cp_list if self._instance_key(x) != instance_key] if cp_list: self.cpdict[mycp] = cp_list else: del self.cpdict[mycp]
def iterAtomsForPackage(self, pkg): """ Find all matching atoms for a given package. This matches virtual arguments against the PROVIDE metadata. This will raise an InvalidDependString exception if PROVIDE is invalid. """ cpv_slot_list = [pkg] cp = cpv_getkey(pkg.cpv) self._load() # make sure the atoms are loaded atoms = self._atommap.get(cp) if atoms: for atom in atoms: if match_from_list(atom, cpv_slot_list): yield atom
def _getPkgAcceptLicense(self, cpv, slot): """ Get an ACCEPT_LICENSE list, accounting for package.license. """ accept_license = self._accept_license cp = cpv_getkey(cpv) cpdict = self._plicensedict.get(cp) if cpdict: cpv_slot = "%s:%s" % (cpv, slot) plicence_list = ordered_by_atom_specificity(cpdict, cpv_slot) if plicence_list: accept_license = list(self._accept_license) for x in plicence_list: accept_license.extend(x) return accept_license
def _getPkgAcceptLicense(self, cpv, slot, repo): """ Get an ACCEPT_LICENSE list, accounting for package.license. """ accept_license = self._accept_license cp = cpv_getkey(cpv) cpdict = self._plicensedict.get(cp) if cpdict: if not hasattr(cpv, "slot"): cpv = _pkg_str(cpv, slot=slot, repo=repo) plicence_list = ordered_by_atom_specificity(cpdict, cpv) if plicence_list: accept_license = list(self._accept_license) for x in plicence_list: accept_license.extend(x) return accept_license
def _populate_treeVirtuals(self, vartree): """ Initialize _treeVirtuals from the given vartree. It must not have been initialized already, otherwise our assumptions about immutability don't hold. """ assert self._treeVirtuals is None, "treeVirtuals must not be reinitialized" self._treeVirtuals = {} for provide, cpv_list in vartree.get_all_provides().items(): try: provide = Atom(provide) except InvalidAtom: continue self._treeVirtuals[provide.cp] = \ [Atom(cpv_getkey(cpv)) for cpv in cpv_list]
def getMaskAtom(self, cpv, slot, repo): """ Take a package and return a matching package.mask atom, or None if no such atom exists or it has been cancelled by package.unmask. PROVIDE is not checked, so atoms will not be found for old-style virtuals. @param cpv: The package name @type cpv: String @param slot: The package's slot @type slot: String @param repo: The package's repository [optional] @type repo: String @rtype: String @return: A matching atom string or None if one is not found. """ cp = cpv_getkey(cpv) return self._getMaskAtom(cpv, slot, repo, self._punmaskdict.get(cp))
def getPKeywords(self, cpv, slot, repo, global_accept_keywords): """Gets any package.keywords settings for cp for the given cpv, slot and repo @param cpv: The package name (for package.keywords support) @type cpv: String @param slot: The 'SLOT' key from the raw package metadata @type slot: String @param keywords: The 'KEYWORDS' key from the raw package metadata @type keywords: String @param global_accept_keywords: The current value of ACCEPT_KEYWORDS @type global_accept_keywords: String @param backuped_accept_keywords: ACCEPT_KEYWORDS from the backup env @type backuped_accept_keywords: String @rtype: List @return: list of KEYWORDS that have been accepted """ pgroups = global_accept_keywords.split() cp = cpv_getkey(cpv) unmaskgroups = [] if self._p_accept_keywords: cpv_slot = "%s:%s" % (cpv, slot) accept_keywords_defaults = tuple('~' + keyword for keyword in \ pgroups if keyword[:1] not in "~-") for d in self._p_accept_keywords: cpdict = d.get(cp) if cpdict: pkg_accept_keywords = \ ordered_by_atom_specificity(cpdict, cpv_slot) if pkg_accept_keywords: for x in pkg_accept_keywords: if not x: x = accept_keywords_defaults unmaskgroups.extend(x) pkgdict = self.pkeywordsdict.get(cp) if pkgdict: cpv_slot = "%s:%s" % (cpv, slot) pkg_accept_keywords = \ ordered_by_atom_specificity(pkgdict, cpv_slot, repo=repo) if pkg_accept_keywords: for x in pkg_accept_keywords: unmaskgroups.extend(x) return unmaskgroups
def getUseMask(self, pkg=None): if pkg is None: return frozenset(stack_lists(self._usemask_list, incremental=True)) cp = getattr(pkg, "cp", None) if cp is None: cp = cpv_getkey(remove_slot(pkg)) usemask = [] for i, pusemask_dict in enumerate(self._pusemask_list): if self._usemask_list[i]: usemask.append(self._usemask_list[i]) cpdict = pusemask_dict.get(cp) if cpdict: pkg_usemask = ordered_by_atom_specificity(cpdict, pkg) if pkg_usemask: usemask.extend(pkg_usemask) return frozenset(stack_lists(usemask, incremental=True))
def getUseForce(self, pkg=None): if pkg is None: return frozenset(stack_lists( self._useforce_list, incremental=True)) cp = getattr(pkg, "cp", None) if cp is None: cp = cpv_getkey(remove_slot(pkg)) useforce = [] for i, puseforce_dict in enumerate(self._puseforce_list): if self._useforce_list[i]: useforce.append(self._useforce_list[i]) cpdict = puseforce_dict.get(cp) if cpdict: pkg_useforce = ordered_by_atom_specificity(cpdict, pkg) if pkg_useforce: useforce.extend(pkg_useforce) return frozenset(stack_lists(useforce, incremental=True))
def rebuild(instmask, args, ldb, dbapi): def _get_enabled(instmask): ret = set() for t in instmask: for d in t: ret.add(d.toString()) return frozenset(ret) def _output_status(cur, length): sys.stderr.write('\rScanning packages: %4d of %4d...' % (cur, length)) def _match_path(vpath, args, enabled): for p in args: ps = p.rstrip(os.path.sep) if vpath == ps or vpath.startswith(ps + os.path.sep): if bool(os.path.exists(vpath)) == bool(p in enabled): return True return False enabled = _get_enabled(instmask) if args: paths = frozenset(expand_ldb(args, ldb)) else: paths = enabled cpvs = dbapi.cpv_all() cpvl = len(cpvs) rebuilds = set() for i, cpv in enumerate(cpvs): _output_status(i, cpvl) dblink = dbapi._dblink(cpv) for f in dblink.getcontents(): if _match_path(f, paths, enabled): key = cpv_getkey(cpv) slot = dbapi.aux_get(cpv, ('SLOT',))[0] rebuilds.add('%s:%s' % (key, slot)) break _output_status(cpvl, cpvl) sys.stderr.write(' done.\n') for r in rebuilds: print(r)
def register(self, cpv, slot, counter, paths): """ Register new objects in the registry. If there is a record with the same packagename (internally derived from cpv) and slot it is overwritten with the new data. @param cpv: package instance that owns the objects @type cpv: CPV (as String) @param slot: the value of SLOT of the given package instance @type slot: String @param counter: vdb counter value for the package instace @type counter: Integer @param paths: absolute paths of objects that got preserved during an update @type paths: List """ cp = cpv_getkey(cpv) cps = cp+":"+slot if len(paths) == 0 and cps in self._data \ and self._data[cps][0] == cpv and int(self._data[cps][1]) == int(counter): del self._data[cps] elif len(paths) > 0: self._data[cps] = (cpv, counter, paths) if self._autocommit: self.store()
def applyDelta(self, data): packages = self._vardb._aux_cache["packages"] deltas = {} for delta in data["deltas"]: cpv = delta["package"] + "-" + delta["version"] deltas[cpv] = delta event = delta["event"] if event == "add": # Use aux_get to populate the cache # for this cpv. if cpv not in packages: try: self._vardb.aux_get(cpv, ["DESCRIPTION"]) except KeyError: pass elif event == "remove": packages.pop(cpv, None) if deltas: # Delete removed or replaced versions from affected slots for cached_cpv, (mtime, metadata) in list(packages.items()): if cached_cpv in deltas: continue removed = False for cpv, delta in deltas.items(): if ( cached_cpv.startswith(delta["package"]) and metadata.get("SLOT") == delta["slot"] and cpv_getkey(cached_cpv) == delta["package"] ): removed = True break if removed: del packages[cached_cpv] del deltas[cpv] if not deltas: break
def register(self, cpv, slot, counter, paths): """ Register new objects in the registry. If there is a record with the same packagename (internally derived from cpv) and slot it is overwritten with the new data. @param cpv: package instance that owns the objects @type cpv: CPV (as String) @param slot: the value of SLOT of the given package instance @type slot: String @param counter: vdb counter value for the package instace @type counter: Integer @param paths: absolute paths of objects that got preserved during an update @type paths: List """ cp = cpv_getkey(cpv) cps = cp + ":" + slot if len(paths) == 0 and cps in self._data \ and self._data[cps][0] == cpv and int(self._data[cps][1]) == int(counter): del self._data[cps] elif len(paths) > 0: self._data[cps] = (cpv, counter, paths) if self._autocommit: self.store()
def _instance_key_multi_instance(self, cpv, support_string=False): try: return (cpv, cpv.build_id, cpv.file_size, cpv.build_time, cpv.mtime) except AttributeError: if not support_string: raise # Fallback for interfaces such as aux_get where API consumers # may pass in a plain string. latest = None for pkg in self.cp_list(cpv_getkey(cpv)): if pkg == cpv and ( latest is None or latest.build_time < pkg.build_time): latest = pkg if latest is not None: return (latest, latest.build_id, latest.file_size, latest.build_time, latest.mtime) raise KeyError(cpv)
def getmaskingstatus(mycpv, settings=None, portdb=None): if settings is None: settings = config(clone=portage.settings) if portdb is None: portdb = portage.portdb metadata = None installed = False if not isinstance(mycpv, basestring): # emerge passed in a Package instance pkg = mycpv mycpv = pkg.cpv metadata = pkg.metadata installed = pkg.installed mysplit = catpkgsplit(mycpv) if not mysplit: raise ValueError(_("invalid CPV: %s") % mycpv) if metadata is None: db_keys = list(portdb._aux_cache_keys) try: metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) except KeyError: if not portdb.cpv_exists(mycpv): raise return ["corruption"] if "?" in metadata["LICENSE"]: settings.setcpv(mycpv, mydb=metadata) metadata["USE"] = settings["PORTAGE_USE"] else: metadata["USE"] = "" rValue = [] # profile checking if settings._getProfileMaskAtom(mycpv, metadata): rValue.append("profile") # package.mask checking if settings._getMaskAtom(mycpv, metadata): rValue.append("package.mask") # keywords checking eapi = metadata["EAPI"] mygroups = settings._getKeywords(mycpv, metadata) licenses = metadata["LICENSE"] properties = metadata["PROPERTIES"] if eapi.startswith("-"): eapi = eapi[1:] if not eapi_is_supported(eapi): return ["EAPI %s" % eapi] elif _eapi_is_deprecated(eapi) and not installed: return ["EAPI %s" % eapi] egroups = settings.configdict["backupenv"].get( "ACCEPT_KEYWORDS", "").split() pgroups = settings["ACCEPT_KEYWORDS"].split() myarch = settings["ARCH"] if pgroups and myarch not in pgroups: """For operating systems other than Linux, ARCH is not necessarily a valid keyword.""" myarch = pgroups[0].lstrip("~") cp = cpv_getkey(mycpv) pkgdict = settings.pkeywordsdict.get(cp) matches = False if pkgdict: cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] for atom, pkgkeywords in pkgdict.items(): if match_from_list(atom, cpv_slot_list): matches = True pgroups.extend(pkgkeywords) if matches or egroups: pgroups.extend(egroups) inc_pgroups = set() for x in pgroups: if x.startswith("-"): if x == "-*": inc_pgroups.clear() else: inc_pgroups.discard(x[1:]) else: inc_pgroups.add(x) pgroups = inc_pgroups del inc_pgroups kmask = "missing" if '**' in pgroups: kmask = None else: for keyword in pgroups: if keyword in mygroups: kmask = None break if kmask: for gp in mygroups: if gp=="*": kmask=None break elif gp=="-"+myarch and myarch in pgroups: kmask="-"+myarch break elif gp=="~"+myarch and myarch in pgroups: kmask="~"+myarch break try: missing_licenses = settings._getMissingLicenses(mycpv, metadata) if missing_licenses: allowed_tokens = set(["||", "(", ")"]) allowed_tokens.update(missing_licenses) license_split = licenses.split() license_split = [x for x in license_split \ if x in allowed_tokens] msg = license_split[:] msg.append("license(s)") rValue.append(" ".join(msg)) except portage.exception.InvalidDependString as e: rValue.append("LICENSE: "+str(e)) try: missing_properties = settings._getMissingProperties(mycpv, metadata) if missing_properties: allowed_tokens = set(["||", "(", ")"]) allowed_tokens.update(missing_properties) properties_split = properties.split() properties_split = [x for x in properties_split \ if x in allowed_tokens] msg = properties_split[:] msg.append("properties") rValue.append(" ".join(msg)) except portage.exception.InvalidDependString as e: rValue.append("PROPERTIES: "+str(e)) # Only show KEYWORDS masks for installed packages # if they're not masked for any other reason. if kmask and (not installed or not rValue): rValue.append(kmask+" keyword") return rValue
def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): """ Takes an unreduced and reduced deplist and removes satisfied dependencies. Returned deplist contains steps that must be taken to satisfy dependencies. """ if trees is None: trees = portage.db writemsg("ZapDeps -- %s\n" % (use_binaries), 2) if not reduced or unreduced == ["||"] or dep_eval(reduced): return [] if unreduced[0] != "||": unresolved = [] for x, satisfied in zip(unreduced, reduced): if isinstance(x, list): unresolved += dep_zapdeps(x, satisfied, myroot, use_binaries=use_binaries, trees=trees) elif not satisfied: unresolved.append(x) return unresolved # We're at a ( || atom ... ) type level and need to make a choice deps = unreduced[1:] satisfieds = reduced[1:] # Our preference order is for an the first item that: # a) contains all unmasked packages with the same key as installed packages # b) contains all unmasked packages # c) contains masked installed packages # d) is the first item preferred_installed = [] preferred_in_graph = [] preferred_any_slot = [] preferred_non_installed = [] unsat_use_in_graph = [] unsat_use_installed = [] unsat_use_non_installed = [] other = [] # unsat_use_* must come after preferred_non_installed # for correct ordering in cases like || ( foo[a] foo[b] ). choice_bins = ( preferred_in_graph, preferred_installed, preferred_any_slot, preferred_non_installed, unsat_use_in_graph, unsat_use_installed, unsat_use_non_installed, other, ) # Alias the trees we'll be checking availability against parent = trees[myroot].get("parent") priority = trees[myroot].get("priority") graph_db = trees[myroot].get("graph_db") vardb = None if "vartree" in trees[myroot]: vardb = trees[myroot]["vartree"].dbapi if use_binaries: mydbapi = trees[myroot]["bintree"].dbapi else: mydbapi = trees[myroot]["porttree"].dbapi # Sort the deps into installed, not installed but already # in the graph and other, not installed and not in the graph # and other, with values of [[required_atom], availablility] for x, satisfied in zip(deps, satisfieds): if isinstance(x, list): atoms = dep_zapdeps(x, satisfied, myroot, use_binaries=use_binaries, trees=trees) else: atoms = [x] if vardb is None: # When called by repoman, we can simply return the first choice # because dep_eval() handles preference selection. return atoms all_available = True all_use_satisfied = True slot_map = {} cp_map = {} for atom in atoms: if atom.blocker: continue # Ignore USE dependencies here since we don't want USE # settings to adversely affect || preference evaluation. avail_pkg = mydbapi.match(atom.without_use) if avail_pkg: avail_pkg = avail_pkg[-1] # highest (ascending order) avail_slot = Atom("%s:%s" % (atom.cp, mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) if not avail_pkg: all_available = False all_use_satisfied = False break if atom.use: avail_pkg_use = mydbapi.match(atom) if not avail_pkg_use: all_use_satisfied = False else: # highest (ascending order) avail_pkg_use = avail_pkg_use[-1] if avail_pkg_use != avail_pkg: avail_pkg = avail_pkg_use avail_slot = Atom("%s:%s" % (atom.cp, mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) slot_map[avail_slot] = avail_pkg pkg_cp = cpv_getkey(avail_pkg) highest_cpv = cp_map.get(pkg_cp) if highest_cpv is None or \ pkgcmp(catpkgsplit(avail_pkg)[1:], catpkgsplit(highest_cpv)[1:]) > 0: cp_map[pkg_cp] = avail_pkg this_choice = (atoms, slot_map, cp_map, all_available) if all_available: # The "all installed" criterion is not version or slot specific. # If any version of a package is already in the graph then we # assume that it is preferred over other possible packages choices. all_installed = True for atom in set(Atom(atom.cp) for atom in atoms \ if not atom.blocker): # New-style virtuals have zero cost to install. if not vardb.match(atom) and not atom.startswith("virtual/"): all_installed = False break all_installed_slots = False if all_installed: all_installed_slots = True for slot_atom in slot_map: # New-style virtuals have zero cost to install. if not vardb.match(slot_atom) and \ not slot_atom.startswith("virtual/"): all_installed_slots = False break if graph_db is None: if all_use_satisfied: if all_installed: if all_installed_slots: preferred_installed.append(this_choice) else: preferred_any_slot.append(this_choice) else: preferred_non_installed.append(this_choice) else: if all_installed_slots: unsat_use_installed.append(this_choice) else: unsat_use_non_installed.append(this_choice) else: all_in_graph = True for slot_atom in slot_map: # New-style virtuals have zero cost to install. if not graph_db.match(slot_atom) and \ not slot_atom.startswith("virtual/"): all_in_graph = False break circular_atom = None if all_in_graph: if parent is None or priority is None: pass elif priority.buildtime: # Check if the atom would result in a direct circular # dependency and try to avoid that if it seems likely # to be unresolvable. This is only relevant for # buildtime deps that aren't already satisfied by an # installed package. cpv_slot_list = [parent] for atom in atoms: if atom.blocker: continue if vardb.match(atom): # If the atom is satisfied by an installed # version then it's not a circular dep. continue if atom.cp != parent.cp: continue if match_from_list(atom, cpv_slot_list): circular_atom = atom break if circular_atom is not None: other.append(this_choice) else: if all_use_satisfied: if all_in_graph: preferred_in_graph.append(this_choice) elif all_installed: if all_installed_slots: preferred_installed.append(this_choice) else: preferred_any_slot.append(this_choice) else: preferred_non_installed.append(this_choice) else: if all_in_graph: unsat_use_in_graph.append(this_choice) elif all_installed_slots: unsat_use_installed.append(this_choice) else: unsat_use_non_installed.append(this_choice) else: other.append(this_choice) # Prefer choices which contain upgrades to higher slots. This helps # for deps such as || ( foo:1 foo:2 ), where we want to prefer the # atom which matches the higher version rather than the atom furthest # to the left. Sorting is done separately for each of choice_bins, so # as not to interfere with the ordering of the bins. Because of the # bin separation, the main function of this code is to allow # --depclean to remove old slots (rather than to pull in new slots). for choices in choice_bins: if len(choices) < 2: continue for choice_1 in choices[1:]: atoms_1, slot_map_1, cp_map_1, all_available_1 = choice_1 cps = set(cp_map_1) for choice_2 in choices: if choice_1 is choice_2: # choice_1 will not be promoted, so move on break atoms_2, slot_map_2, cp_map_2, all_available_2 = choice_2 intersecting_cps = cps.intersection(cp_map_2) if not intersecting_cps: continue has_upgrade = False has_downgrade = False for cp in intersecting_cps: version_1 = cp_map_1[cp] version_2 = cp_map_2[cp] difference = pkgcmp(catpkgsplit(version_1)[1:], catpkgsplit(version_2)[1:]) if difference != 0: if difference > 0: has_upgrade = True else: has_downgrade = True break if has_upgrade and not has_downgrade: # promote choice_1 in front of choice_2 choices.remove(choice_1) index_2 = choices.index(choice_2) choices.insert(index_2, choice_1) break for allow_masked in (False, True): for choices in choice_bins: for atoms, slot_map, cp_map, all_available in choices: if all_available or allow_masked: return atoms assert(False) # This point should not be reachable
def getmaskingstatus(mycpv, settings=None, portdb=None): if settings is None: settings = config(clone=portage.settings) if portdb is None: portdb = portage.portdb metadata = None installed = False if not isinstance(mycpv, basestring): # emerge passed in a Package instance pkg = mycpv mycpv = pkg.cpv metadata = pkg.metadata installed = pkg.installed mysplit = catpkgsplit(mycpv) if not mysplit: raise ValueError(_("invalid CPV: %s") % mycpv) if metadata is None: db_keys = list(portdb._aux_cache_keys) try: metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) except KeyError: if not portdb.cpv_exists(mycpv): raise return ["corruption"] if "?" in metadata["LICENSE"]: settings.setcpv(mycpv, mydb=metadata) metadata["USE"] = settings["PORTAGE_USE"] else: metadata["USE"] = "" rValue = [] # profile checking if settings._getProfileMaskAtom(mycpv, metadata): rValue.append("profile") # package.mask checking if settings._getMaskAtom(mycpv, metadata): rValue.append("package.mask") # keywords checking eapi = metadata["EAPI"] mygroups = settings._getKeywords(mycpv, metadata) licenses = metadata["LICENSE"] properties = metadata["PROPERTIES"] if eapi.startswith("-"): eapi = eapi[1:] if not eapi_is_supported(eapi): return ["EAPI %s" % eapi] elif _eapi_is_deprecated(eapi) and not installed: return ["EAPI %s" % eapi] egroups = settings.configdict["backupenv"].get("ACCEPT_KEYWORDS", "").split() pgroups = settings["ACCEPT_KEYWORDS"].split() myarch = settings["ARCH"] if pgroups and myarch not in pgroups: """For operating systems other than Linux, ARCH is not necessarily a valid keyword.""" myarch = pgroups[0].lstrip("~") cp = cpv_getkey(mycpv) pkgdict = settings.pkeywordsdict.get(cp) matches = False if pkgdict: cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] for atom, pkgkeywords in pkgdict.items(): if match_from_list(atom, cpv_slot_list): matches = True pgroups.extend(pkgkeywords) if matches or egroups: pgroups.extend(egroups) inc_pgroups = set() for x in pgroups: if x.startswith("-"): if x == "-*": inc_pgroups.clear() else: inc_pgroups.discard(x[1:]) else: inc_pgroups.add(x) pgroups = inc_pgroups del inc_pgroups kmask = "missing" if '**' in pgroups: kmask = None else: for keyword in pgroups: if keyword in mygroups: kmask = None break if kmask: for gp in mygroups: if gp == "*": kmask = None break elif gp == "-" + myarch and myarch in pgroups: kmask = "-" + myarch break elif gp == "~" + myarch and myarch in pgroups: kmask = "~" + myarch break try: missing_licenses = settings._getMissingLicenses(mycpv, metadata) if missing_licenses: allowed_tokens = set(["||", "(", ")"]) allowed_tokens.update(missing_licenses) license_split = licenses.split() license_split = [x for x in license_split \ if x in allowed_tokens] msg = license_split[:] msg.append("license(s)") rValue.append(" ".join(msg)) except portage.exception.InvalidDependString as e: rValue.append("LICENSE: " + str(e)) try: missing_properties = settings._getMissingProperties(mycpv, metadata) if missing_properties: allowed_tokens = set(["||", "(", ")"]) allowed_tokens.update(missing_properties) properties_split = properties.split() properties_split = [x for x in properties_split \ if x in allowed_tokens] msg = properties_split[:] msg.append("properties") rValue.append(" ".join(msg)) except portage.exception.InvalidDependString as e: rValue.append("PROPERTIES: " + str(e)) # Only show KEYWORDS masks for installed packages # if they're not masked for any other reason. if kmask and (not installed or not rValue): rValue.append(kmask + " keyword") return rValue
def key(self): return PortageBoundPackageKey(cpv_getkey(self._cpv), self)
def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): """ Takes an unreduced and reduced deplist and removes satisfied dependencies. Returned deplist contains steps that must be taken to satisfy dependencies. """ if trees is None: trees = portage.db writemsg("ZapDeps -- %s\n" % (use_binaries), 2) if not reduced or unreduced == ["||"] or dep_eval(reduced): return [] if unreduced[0] != "||": unresolved = [] for x, satisfied in zip(unreduced, reduced): if isinstance(x, list): unresolved += dep_zapdeps(x, satisfied, myroot, use_binaries=use_binaries, trees=trees) elif not satisfied: unresolved.append(x) return unresolved # We're at a ( || atom ... ) type level and need to make a choice deps = unreduced[1:] satisfieds = reduced[1:] # Our preference order is for an the first item that: # a) contains all unmasked packages with the same key as installed packages # b) contains all unmasked packages # c) contains masked installed packages # d) is the first item preferred_installed = [] preferred_in_graph = [] preferred_any_slot = [] preferred_non_installed = [] unsat_use_in_graph = [] unsat_use_installed = [] unsat_use_non_installed = [] other = [] # unsat_use_* must come after preferred_non_installed # for correct ordering in cases like || ( foo[a] foo[b] ). choice_bins = ( preferred_in_graph, preferred_installed, preferred_any_slot, preferred_non_installed, unsat_use_in_graph, unsat_use_installed, unsat_use_non_installed, other, ) # Alias the trees we'll be checking availability against parent = trees[myroot].get("parent") priority = trees[myroot].get("priority") graph_db = trees[myroot].get("graph_db") vardb = None if "vartree" in trees[myroot]: vardb = trees[myroot]["vartree"].dbapi if use_binaries: mydbapi = trees[myroot]["bintree"].dbapi else: mydbapi = trees[myroot]["porttree"].dbapi # Sort the deps into installed, not installed but already # in the graph and other, not installed and not in the graph # and other, with values of [[required_atom], availablility] for x, satisfied in zip(deps, satisfieds): if isinstance(x, list): atoms = dep_zapdeps(x, satisfied, myroot, use_binaries=use_binaries, trees=trees) else: atoms = [x] if vardb is None: # When called by repoman, we can simply return the first choice # because dep_eval() handles preference selection. return atoms all_available = True all_use_satisfied = True slot_map = {} cp_map = {} for atom in atoms: if atom.blocker: continue # Ignore USE dependencies here since we don't want USE # settings to adversely affect || preference evaluation. avail_pkg = mydbapi.match(atom.without_use) if avail_pkg: avail_pkg = avail_pkg[-1] # highest (ascending order) avail_slot = Atom( "%s:%s" % (atom.cp, mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) if not avail_pkg: all_available = False all_use_satisfied = False break if atom.use: avail_pkg_use = mydbapi.match(atom) if not avail_pkg_use: all_use_satisfied = False else: # highest (ascending order) avail_pkg_use = avail_pkg_use[-1] if avail_pkg_use != avail_pkg: avail_pkg = avail_pkg_use avail_slot = Atom( "%s:%s" % (atom.cp, mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) slot_map[avail_slot] = avail_pkg pkg_cp = cpv_getkey(avail_pkg) highest_cpv = cp_map.get(pkg_cp) if highest_cpv is None or \ pkgcmp(catpkgsplit(avail_pkg)[1:], catpkgsplit(highest_cpv)[1:]) > 0: cp_map[pkg_cp] = avail_pkg this_choice = (atoms, slot_map, cp_map, all_available) if all_available: # The "all installed" criterion is not version or slot specific. # If any version of a package is already in the graph then we # assume that it is preferred over other possible packages choices. all_installed = True for atom in set(Atom(atom.cp) for atom in atoms \ if not atom.blocker): # New-style virtuals have zero cost to install. if not vardb.match(atom) and not atom.startswith("virtual/"): all_installed = False break all_installed_slots = False if all_installed: all_installed_slots = True for slot_atom in slot_map: # New-style virtuals have zero cost to install. if not vardb.match(slot_atom) and \ not slot_atom.startswith("virtual/"): all_installed_slots = False break if graph_db is None: if all_use_satisfied: if all_installed: if all_installed_slots: preferred_installed.append(this_choice) else: preferred_any_slot.append(this_choice) else: preferred_non_installed.append(this_choice) else: if all_installed_slots: unsat_use_installed.append(this_choice) else: unsat_use_non_installed.append(this_choice) else: all_in_graph = True for slot_atom in slot_map: # New-style virtuals have zero cost to install. if not graph_db.match(slot_atom) and \ not slot_atom.startswith("virtual/"): all_in_graph = False break circular_atom = None if all_in_graph: if parent is None or priority is None: pass elif priority.buildtime: # Check if the atom would result in a direct circular # dependency and try to avoid that if it seems likely # to be unresolvable. This is only relevant for # buildtime deps that aren't already satisfied by an # installed package. cpv_slot_list = [parent] for atom in atoms: if atom.blocker: continue if vardb.match(atom): # If the atom is satisfied by an installed # version then it's not a circular dep. continue if atom.cp != parent.cp: continue if match_from_list(atom, cpv_slot_list): circular_atom = atom break if circular_atom is not None: other.append(this_choice) else: if all_use_satisfied: if all_in_graph: preferred_in_graph.append(this_choice) elif all_installed: if all_installed_slots: preferred_installed.append(this_choice) else: preferred_any_slot.append(this_choice) else: preferred_non_installed.append(this_choice) else: if all_in_graph: unsat_use_in_graph.append(this_choice) elif all_installed_slots: unsat_use_installed.append(this_choice) else: unsat_use_non_installed.append(this_choice) else: other.append(this_choice) # Prefer choices which contain upgrades to higher slots. This helps # for deps such as || ( foo:1 foo:2 ), where we want to prefer the # atom which matches the higher version rather than the atom furthest # to the left. Sorting is done separately for each of choice_bins, so # as not to interfere with the ordering of the bins. Because of the # bin separation, the main function of this code is to allow # --depclean to remove old slots (rather than to pull in new slots). for choices in choice_bins: if len(choices) < 2: continue for choice_1 in choices[1:]: atoms_1, slot_map_1, cp_map_1, all_available_1 = choice_1 cps = set(cp_map_1) for choice_2 in choices: if choice_1 is choice_2: # choice_1 will not be promoted, so move on break atoms_2, slot_map_2, cp_map_2, all_available_2 = choice_2 intersecting_cps = cps.intersection(cp_map_2) if not intersecting_cps: continue has_upgrade = False has_downgrade = False for cp in intersecting_cps: version_1 = cp_map_1[cp] version_2 = cp_map_2[cp] difference = pkgcmp( catpkgsplit(version_1)[1:], catpkgsplit(version_2)[1:]) if difference != 0: if difference > 0: has_upgrade = True else: has_downgrade = True break if has_upgrade and not has_downgrade: # promote choice_1 in front of choice_2 choices.remove(choice_1) index_2 = choices.index(choice_2) choices.insert(index_2, choice_1) break for allow_masked in (False, True): for choices in choice_bins: for atoms, slot_map, cp_map, all_available in choices: if all_available or allow_masked: return atoms assert (False) # This point should not be reachable