From a2e061425e9c402eb9f0101f17ce78c397f2efef Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sat, 9 Feb 2008 06:26:39 +0000 Subject: Bug #208708 - Show informative warning messages for installed packages that are masked. (trunk r9301) svn path=/main/branches/2.1.2/; revision=9302 --- bin/emerge | 201 ++++++++++++++++++++++++++++++++++++++++----------------- pym/portage.py | 9 ++- 2 files changed, 150 insertions(+), 60 deletions(-) diff --git a/bin/emerge b/bin/emerge index 0536fb1cb..3ed0211e5 100755 --- a/bin/emerge +++ b/bin/emerge @@ -1147,6 +1147,111 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False): return False return True +def get_masking_status(pkg, pkgsettings, root_config): + + mreasons = portage.getmaskingstatus( + pkg.cpv, metadata=pkg.metadata, settings=pkgsettings, + portdb=root_config.trees["porttree"].dbapi) + + if pkg.built and \ + pkg.metadata["CHOST"] != root_config.settings["CHOST"]: + mreasons.append("CHOST: %s" % \ + pkg.metadata["CHOST"]) + + if not pkg.metadata["SLOT"]: + mreasons.append("invalid: SLOT is undefined") + + return mreasons + +def get_mask_info(root_config, cpv, pkgsettings, + db, pkg_type, built, installed, db_keys): + eapi_masked = False + try: + metadata = dict(izip(db_keys, + db.aux_get(cpv, db_keys))) + except KeyError: + metadata = None + if metadata and not built: + pkgsettings.setcpv(cpv, mydb=metadata) + metadata["USE"] = pkgsettings.get("USE", "") + if metadata is None: + mreasons = ["corruption"] + else: + pkg = Package(type_name=pkg_type, root=root_config.root, + cpv=cpv, built=built, metadata=metadata) + mreasons = get_masking_status(pkg, pkgsettings, root_config) + return metadata, mreasons + +def show_masked_packages(masked_packages): + shown_licenses = set() + shown_comments = set() + # Maybe there is both an ebuild and a binary. Only + # show one of them to avoid redundant appearance. + shown_cpvs = set() + have_eapi_mask = False + for (root_config, pkgsettings, cpv, + metadata, mreasons) in masked_packages: + if cpv in shown_cpvs: + continue + shown_cpvs.add(cpv) + comment, filename = None, None + if "package.mask" in mreasons: + comment, filename = \ + portage.getmaskingreason( + cpv, metadata=metadata, + settings=pkgsettings, + portdb=root_config.trees["porttree"].dbapi, + return_location=True) + missing_licenses = [] + if metadata: + if not portage.eapi_is_supported(metadata["EAPI"]): + have_eapi_mask = True + + print "- "+cpv+" (masked by: "+", ".join(mreasons)+")" + if comment and comment not in shown_comments: + print filename+":" + print comment + shown_comments.add(comment) + return have_eapi_mask + +class Package(object): + __slots__ = ("__weakref__", "built", "cpv", "depth", + "installed", "metadata", "root", "onlydeps", "type_name", + "cpv_slot", "slot_atom", "_digraph_node") + def __init__(self, **kwargs): + for myattr in self.__slots__: + if myattr == "__weakref__": + continue + myvalue = kwargs.get(myattr, None) + setattr(self, myattr, myvalue) + + self.slot_atom = "%s:%s" % \ + (portage.cpv_getkey(self.cpv), self.metadata["SLOT"]) + + self.cpv_slot = "%s:%s" % (self.cpv, self.metadata["SLOT"]) + + status = "merge" + if self.onlydeps or self.installed: + status = "nomerge" + self._digraph_node = (self.type_name, self.root, self.cpv, status) + + def __eq__(self, other): + return self._digraph_node == other + def __ne__(self, other): + return self._digraph_node != other + def __hash__(self): + return hash(self._digraph_node) + def __len__(self): + return len(self._digraph_node) + def __getitem__(self, key): + return self._digraph_node[key] + def __iter__(self): + return iter(self._digraph_node) + def __contains__(self, key): + return key in self._digraph_node + def __str__(self): + return str(self._digraph_node) + class BlockerCache(DictMixin): """This caches blockers of installed packages so that dep_check does not have to be done for every single installed package on every invocation of @@ -1377,6 +1482,7 @@ class depgraph: self._altlist_cache = {} self._pprovided_args = [] self._missing_args = [] + self._masked_installed = [] def _show_slot_collision_notice(self): """Show an informational message advising the user to mask one of the @@ -1658,8 +1764,6 @@ class depgraph: del e return 0 - if arg: - self._set_nodes.add(jbigkey) built = mytype != "ebuild" installed = mytype == "installed" if installed: @@ -1675,20 +1779,27 @@ class depgraph: # - multi-slot atoms listed in the world file # to prevent depclean from removing them - installed_masked = not visible( - pkgsettings, mykey, metadata, - built=built, installed=installed) + if arg: + all_ebuilds_masked = bool( + portdb.xmatch("match-all", arg) and + not portdb.xmatch("bestmatch-visible", arg)) + if all_ebuilds_masked: + self._missing_args.append(arg) - all_ebuilds_masked = bool( - portdb.xmatch("match-all", arg) and - not portdb.xmatch("bestmatch-visible", arg)) + if "selective" not in self.myparams: + self._show_unsatisfied_dep(myroot, arg) + return 0 - if installed_masked or all_ebuilds_masked: - self._missing_args.append(arg) + pkg = Package(type_name=mytype, root=myroot, + cpv=mykey, built=built, installed=installed, + metadata=metadata) - if "selective" not in self.myparams: - self._show_unsatisfied_dep(myroot, arg) - return 0 + if not visible(pkgsettings, pkg.cpv, pkg.metadata, + built=pkg.built, installed=pkg.installed): + self._masked_installed.append((pkg, pkgsettings)) + + if arg: + self._set_nodes.add(jbigkey) # Do this even when addme is False (--onlydeps) so that the # parent/child relationship is always known in case @@ -2014,9 +2125,9 @@ class depgraph: red(' [%s]' % myparent[0]) + ')' masked_packages = [] missing_licenses = [] - from textwrap import wrap have_eapi_mask = False pkgsettings = self.pkgsettings[root] + root_config = self.roots[root] portdb = self.roots[root].trees["porttree"].dbapi dbs = [] portdb = self.trees[root]["porttree"].dbapi @@ -2040,59 +2151,22 @@ class depgraph: # descending order cpv_list.reverse() for cpv in cpv_list: - try: - metadata = dict(izip(db_keys, - db.aux_get(cpv, db_keys))) - except KeyError: - mreasons = ["corruption"] - metadata = None - mreasons = portage.getmaskingstatus( - cpv, metadata=metadata, - settings=pkgsettings, portdb=portdb) - comment, filename = None, None - if "package.mask" in mreasons: - comment, filename = \ - portage.getmaskingreason( - cpv, metadata=metadata, - settings=pkgsettings, portdb=portdb, - return_location=True) - if built and \ - metadata["CHOST"] != pkgsettings["CHOST"]: - mreasons.append("CHOST: %s" % \ - metadata["CHOST"]) - missing_licenses = [] - if metadata: - if not metadata["SLOT"]: - mreasons.append("invalid: SLOT is undefined") - if not portage.eapi_is_supported(metadata["EAPI"]): - have_eapi_mask = True - if not mreasons: - continue - masked_packages.append((cpv, mreasons, - comment, filename, missing_licenses)) + metadata, mreasons = get_mask_info(root_config, cpv, + pkgsettings, db, pkg_type, built, installed, db_keys) + masked_packages.append( + (root_config, pkgsettings, cpv, metadata, mreasons)) + if masked_packages: print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") print "!!! One of the following masked packages is required to complete your request:" - shown_licenses = set() - shown_comments = set() - # Maybe there is both an ebuild and a binary. Only - # show one of them to avoid redundant appearance. - shown_cpvs = set() - for cpv, mreasons, comment, filename, missing_licenses in masked_packages: - if cpv in shown_cpvs: - continue - shown_cpvs.add(cpv) - print "- "+cpv+" (masked by: "+", ".join(mreasons)+")" - if comment and comment not in shown_comments: - print filename+":" - print comment - shown_comments.add(comment) + have_eapi_mask = show_masked_packages(masked_packages) if have_eapi_mask: print msg = ("The current version of portage supports " + \ "EAPI '%s'. You must upgrade to a newer version" + \ " of portage before EAPI masked packages can" + \ " be installed.") % portage_const.EAPI + from textwrap import wrap for line in wrap(msg, 75): print line print @@ -2959,6 +3033,17 @@ class depgraph: except portage_exception.PackageNotFound: missing_atoms.append(mydep) + masked_packages = [] + for pkg, pkgsettings in self._masked_installed: + root_config = self.roots[pkg.root] + mreasons = get_masking_status(pkg, pkgsettings, root_config) + masked_packages.append((root_config, pkgsettings, + pkg.cpv, pkg.metadata, mreasons)) + if masked_packages: + sys.stderr.write("\n" + colorize("BAD", "!!!") + \ + " The following installed packages are masked:\n") + show_masked_packages(masked_packages) + if not self.validate_blockers(): return False diff --git a/pym/portage.py b/pym/portage.py index 43dc6704e..e27e30a3d 100644 --- a/pym/portage.py +++ b/pym/portage.py @@ -1877,7 +1877,11 @@ class config: pkginternaluse = "" iuse = "" if mydb: - slot, iuse = mydb.aux_get(self.mycpv, ["SLOT", "IUSE"]) + if isinstance(mydb, dict): + slot = mydb["SLOT"] + iuse = mydb["IUSE"] + else: + slot, iuse = mydb.aux_get(self.mycpv, ["SLOT", "IUSE"]) cpv_slot = "%s:%s" % (self.mycpv, slot) pkginternaluse = [] for x in iuse.split(): @@ -6891,7 +6895,8 @@ class portdbapi(dbapi): self.auxdb[x] = self.auxdbmodule( self.depcachedir, x, filtered_auxdbkeys, gid=portage_gid) # Selectively cache metadata in order to optimize dep matching. - self._aux_cache_keys = set(["EAPI", "KEYWORDS", "SLOT"]) + self._aux_cache_keys = set( + ["EAPI", "IUSE", "KEYWORDS", "LICENSE", "PROVIDE", "SLOT"]) self._aux_cache = {} self._broken_ebuilds = set() -- cgit v1.2.3-1-g7c22