Merged from trunk 9637:9665
authorFabian Groffen <grobian@gentoo.org>
Tue, 1 Apr 2008 18:27:32 +0000 (18:27 -0000)
committerFabian Groffen <grobian@gentoo.org>
Tue, 1 Apr 2008 18:27:32 +0000 (18:27 -0000)
   | 9643    | Pass Package instances into visible() so that the package    |
   | zmedico | instance can be used to cache relevant visibility            |
   |         | information such as whether or not the package is corrupt or |
   |         | otherwise invalid.                                           |

   | 9644    | Replace an package tuple with a real Package instance.       |
   | zmedico |                                                              |

   | 9645    | Make depgraph creation more tolerant of missing or masked    |
   | zmedico | packages when the relevant deps are satisfied by installed   |
   |         | packages. This kind of friendliness is especially desired in |
   |         | cases such as --emptytree where it might not be possible to  |
   |         | reinstall every single package. Also, it allows multislot    |
   |         | atoms from the world file (that are necessary to prevent     |
   |         | them from being removed by depclean) trigger warning         |
   |         | messages while still allowing a --emptytree to proceed.      |

   | 9646    | Bug #197810 - Fix package selection logic so that it will    |
   | zmedico | always fall back to an installed package when necessary.     |

   | 9648    | When selecting packages and there is a mixture of old-style  |
   | zmedico | and new-style virtual matches, filter out the old-style      |
   |         | virtual matches.                                             |

   | 9650    | Remove some redundant and obsolete code for warning about    |
   | zmedico | installed packages pulled into the graph.                    |

   | 9652    | Fix package selection logic to always properly reject the    |
   | zmedico | installed package when another is available and the user     |
   |         | wants to reinstall.                                          |

   | 9654    | In the package selection loop, move the installed package    |
   | zmedico | rejection code as early as possible.                         |

   | 9656    | When deps are forced to be satisfied by installed packages   |
   | zmedico | due to masking or unavailability, only tolerate it when the  |
   |         | atom comes from either the system or world set since         |
   |         | otherwise it's a good idea to bail so that the user can      |
   |         | correct the problem.                                         |

   | 9658    | Bug #215308 - Cache the paths of known bad manifests to      |
   | zmedico | ensure that the same broken manifest is never checked twice. |

   | 9660    | When identifying a sys-apps/portage node, compare category   |
   | zmedico | too (not just "portage".                                     |

   | 9662    | Handle missing LICENSE in the Packages index since that's    |
   | zmedico | allowed for virtual packages.                                |

   | 9665    | Exploid ascending order returned from dbapi.match() calls to |
   | zmedico | avoid the need to call best().                               |

svn path=/main/branches/prefix/; revision=9668

pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/bintree.py

index 14de631490119cae6f42bcd6af4517edb3d161a3..06727799b9b355abe4f862943851c8a3a3917340 100644 (file)
@@ -481,8 +481,14 @@ class search(object):
        def _visible(self, db, cpv, metadata):
                installed = db is self.vartree.dbapi
                built = installed or db is not self._portdb
-               return visible(self.settings, cpv, metadata,
-                       built=built, installed=installed)
+               pkg_type = "ebuild"
+               if installed:
+                       pkg_type = "installed"
+               elif built:
+                       pkg_type = "binary"
+               return visible(self.settings,
+                       Package(type_name=pkg_type, root=self.settings["ROOT"],
+                       cpv=cpv, built=built, installed=installed, metadata=metadata))
 
        def _xmatch(self, level, atom):
                """
@@ -1061,7 +1067,7 @@ def perform_global_updates(mycpv, mydb, mycommands):
        if updates:
                mydb.aux_update(mycpv, updates)
 
-def visible(pkgsettings, cpv, metadata, built=False, installed=False):
+def visible(pkgsettings, pkg):
        """
        Check if a package is visible. This can raise an InvalidDependString
        exception if LICENSE is invalid.
@@ -1069,26 +1075,30 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False):
        @rtype: Boolean
        @returns: True if the package is visible, False otherwise.
        """
-       if not metadata["SLOT"]:
+       if not pkg.metadata["SLOT"]:
                return False
-       if built and not installed and \
-               metadata["CHOST"] != pkgsettings["CHOST"]:
+       if pkg.built and not pkg.installed and \
+               pkg.metadata["CHOST"] != pkgsettings["CHOST"]:
                return False
        if built and not installed:
                # we can have an old binary which has no EPREFIX information
-               if "EPREFIX" not in metadata or not metadata["EPREFIX"]:
+               if "EPREFIX" not in pkg.metadata or not pkg.metadata["EPREFIX"]:
                        return False
-               if len(metadata["EPREFIX"].strip()) < len(pkgsettings["EPREFIX"]):
+               if len(pkg.metadata["EPREFIX"].strip()) < len(pkgsettings["EPREFIX"]):
                        return False
-       if not portage.eapi_is_supported(metadata["EAPI"]):
+       if not portage.eapi_is_supported(pkg.metadata["EAPI"]):
                return False
-       if not installed and pkgsettings.getMissingKeywords(cpv, metadata):
+       if not pkg.installed and \
+               pkgsettings.getMissingKeywords(pkg.cpv, pkg.metadata):
                return False
-       if pkgsettings.getMaskAtom(cpv, metadata):
+       if pkgsettings.getMaskAtom(pkg.cpv, pkg.metadata):
                return False
-       if pkgsettings.getProfileMaskAtom(cpv, metadata):
+       if pkgsettings.getProfileMaskAtom(pkg.cpv, pkg.metadata):
                return False
-       if pkgsettings.getMissingLicenses(cpv, metadata):
+       try:
+               if pkgsettings.getMissingLicenses(pkg.cpv, pkg.metadata):
+                       return False
+       except portage.exception.InvalidDependString:
                return False
        return True
 
@@ -1201,7 +1211,7 @@ def iter_atoms(deps):
 class Package(object):
        __slots__ = ("__weakref__", "built", "cpv", "depth",
                "installed", "metadata", "root", "onlydeps", "type_name",
-               "cpv_slot", "slot_atom", "_digraph_node")
+               "cp", "cpv_slot", "slot_atom", "_digraph_node")
        def __init__(self, **kwargs):
                for myattr in self.__slots__:
                        if myattr == "__weakref__":
@@ -1209,9 +1219,8 @@ class Package(object):
                        myvalue = kwargs.get(myattr, None)
                        setattr(self, myattr, myvalue)
 
-               self.slot_atom = "%s:%s" % \
-                       (portage.cpv_getkey(self.cpv), self.metadata["SLOT"])
-
+               self.cp = portage.cpv_getkey(self.cpv)
+               self.slot_atom = "%s:%s" % (self.cp, self.metadata["SLOT"])
                self.cpv_slot = "%s:%s" % (self.cpv, self.metadata["SLOT"])
 
                status = "merge"
@@ -1839,30 +1848,9 @@ class depgraph(object):
                                        return 0
 
                if pkg.installed:
-                       # Warn if all matching ebuilds are masked or
-                       # the installed package itself is masked. Do
-                       # not warn if there are simply no matching
-                       # ebuilds since that would be annoying in some
-                       # cases:
-                       #
-                       #  - binary packages installed from an overlay
-                       #    that is not listed in PORTDIR_OVERLAY
-                       #
-                       #  - multi-slot atoms listed in the world file
-                       #    to prevent depclean from removing them
-
-                       if arg_atoms:
-                               selective = "selective" in self.myparams
-                               portdb = self.trees[pkg.root]["porttree"].dbapi
-                               for arg, atom in arg_atoms:
-                                       all_ebuilds_masked = bool(
-                                               portdb.xmatch("match-all", atom) and
-                                               not portdb.xmatch("bestmatch-visible", atom))
-                                       if all_ebuilds_masked and not selective:
-                                               self._missing_args.append((arg, atom))
-
-                       if not visible(pkgsettings, pkg.cpv, pkg.metadata,
-                               built=pkg.built, installed=pkg.installed):
+                       # Warn if an installed package is masked and it
+                       # is pulled into the graph.
+                       if not visible(pkgsettings, pkg):
                                self._masked_installed.append((pkg, pkgsettings))
 
                if args:
@@ -2305,7 +2293,15 @@ class depgraph(object):
                                        if pkg.installed and "selective" not in self.myparams:
                                                self._unsatisfied_deps_for_display.append(
                                                        ((myroot, atom), {}))
-                                               return 0, myfavorites
+                                               # Previous behavior was to bail out in this case, but
+                                               # since the dep is satisfied by the installed package,
+                                               # it's more friendly to continue building the graph
+                                               # and just show a warning message. Therefore, only bail
+                                               # out here if the atom is not from either the system or
+                                               # world set.
+                                               if not (isinstance(arg, SetArg) and \
+                                                       arg.name in ("system", "world")):
+                                                       return 0, myfavorites
 
                                        self._dep_stack.append(
                                                Dependency(atom=atom, onlydeps=onlydeps, root=myroot, parent=arg))
@@ -2443,12 +2439,9 @@ class depgraph(object):
                                                else:
                                                        metadata["USE"] = ""
 
-                                       try:
-                                               if not visible(pkgsettings, cpv, metadata,
-                                                       built=built, installed=installed):
-                                                       continue
-                                       except portage.exception.InvalidDependString:
-                                               # masked by corruption
+                                       if not visible(pkgsettings, Package(built=built,
+                                               cpv=cpv, root=myroot, type_name=pkg_type,
+                                               installed=installed, metadata=metadata)):
                                                continue
 
                                        filtered_db.cpv_inject(cpv, metadata=metadata)
@@ -2591,7 +2584,6 @@ class depgraph(object):
                empty = "empty" in self.myparams
                selective = "selective" in self.myparams
                noreplace = "--noreplace" in self.myopts
-               reinstall = False
                # Behavior of the "selective" parameter depends on
                # whether or not a package matches an argument atom.
                # If an installed package provides an old-style
@@ -2610,14 +2602,11 @@ class depgraph(object):
                        for db, pkg_type, built, installed, db_keys in dbs:
                                if existing_node:
                                        break
-                               if installed and not find_existing_node and \
-                                       (reinstall or not selective) and \
-                                       (matched_packages or empty):
-                                       # We only need to select an installed package in the
-                                       # following cases:
-                                       #   1) there is no other choice
-                                       #   2) selective is True
-                                       continue
+                               if installed and not find_existing_node:
+                                       want_reinstall = empty or \
+                                               (found_available_arg and not selective)
+                                       if want_reinstall and matched_packages:
+                                               continue
                                if hasattr(db, "xmatch"):
                                        cpv_list = db.xmatch("match-all", atom)
                                else:
@@ -2656,12 +2645,9 @@ class depgraph(object):
                                        if not installed:
                                                if myarg:
                                                        found_available_arg = True
-                                               try:
-                                                       if not visible(pkgsettings, cpv, metadata,
-                                                               built=built, installed=installed):
-                                                               continue
-                                               except portage.exception.InvalidDependString:
-                                                       # masked by corruption
+                                               if not visible(pkgsettings, Package(built=built,
+                                                       cpv=cpv, installed=installed, metadata=metadata,
+                                                       type_name=pkg_type)):
                                                        continue
                                        # At this point, we've found the highest visible
                                        # match from the current repo. Any lower versions
@@ -2713,7 +2699,7 @@ class depgraph(object):
                                        if not installed and \
                                                ("--newuse" in self.myopts or \
                                                "--reinstall" in self.myopts) and \
-                                               vardb.cpv_exists(cpv):
+                                               cpv in vardb.match(atom):
                                                pkgsettings.setcpv(cpv, mydb=metadata)
                                                forced_flags = set()
                                                forced_flags.update(pkgsettings.useforce)
@@ -2728,8 +2714,6 @@ class depgraph(object):
                                                        self._reinstall_for_flags(
                                                        forced_flags, old_use, old_iuse,
                                                        cur_use, cur_iuse)
-                                               if reinstall_for_flags:
-                                                       reinstall = True
                                        if not installed:
                                                must_reinstall = empty or \
                                                        (myarg and not selective)
@@ -2737,11 +2721,6 @@ class depgraph(object):
                                                        not must_reinstall and \
                                                        cpv in vardb.match(atom):
                                                        break
-                                       if installed:
-                                               must_reinstall = empty or \
-                                                       (found_available_arg and not selective)
-                                               if must_reinstall:
-                                                       break
                                        # Metadata accessed above is cached internally by
                                        # each db in order to optimize visibility checks.
                                        # Now that all possible checks visibility checks
@@ -2754,14 +2733,13 @@ class depgraph(object):
                                                pkgsettings.setcpv(cpv, mydb=metadata)
                                                metadata["USE"] = pkgsettings["PORTAGE_USE"]
                                                myeb = cpv
-                                       matched_packages.append(
-                                               Package(type_name=pkg_type, root=root,
-                                                       cpv=cpv, metadata=metadata,
-                                                       built=built, installed=installed,
-                                                       onlydeps=onlydeps))
+                                       pkg = Package(type_name=pkg_type, root=root,
+                                               cpv=cpv, metadata=metadata,
+                                               built=built, installed=installed,
+                                               onlydeps=onlydeps)
+                                       matched_packages.append(pkg)
                                        if reinstall_for_flags:
-                                               pkg_node = (pkg_type, root, cpv, "merge")
-                                               self._reinstall_nodes[pkg_node] = \
+                                               self._reinstall_nodes[pkg] = \
                                                        reinstall_for_flags
                                        break
 
@@ -2772,11 +2750,25 @@ class depgraph(object):
                        for pkg in matched_packages:
                                print (pkg.type_name + ":").rjust(10), pkg.cpv
 
+               # Filter out any old-style virtual matches if they are
+               # mixed with new-style virtual matches.
+               cp = portage.dep_getkey(atom)
+               if len(matched_packages) > 1 and \
+                       "virtual" == portage.catsplit(cp)[0]:
+                       for pkg in matched_packages:
+                               if pkg.cp != cp:
+                                       continue
+                               # Got a new-style virtual, so filter
+                               # out any old-style virtuals.
+                               matched_packages = [pkg for pkg in matched_packages \
+                                       if pkg.cp == cp]
+                               break
+
                if len(matched_packages) > 1:
                        bestmatch = portage.best(
                                [pkg.cpv for pkg in matched_packages])
                        matched_packages = [pkg for pkg in matched_packages \
-                               if pkg.cpv == bestmatch]
+                               if portage.dep.cpvequal(pkg.cpv, bestmatch)]
 
                # ordered by type preference ("ebuild" type is the last resort)
                return  matched_packages[-1], existing_node
@@ -3188,8 +3180,7 @@ class depgraph(object):
                        get_nodes = mygraph.leaf_nodes
                        for node in mygraph.order:
                                if node.root == "/" and \
-                                       "portage" == portage.catsplit(
-                                       portage.cpv_getkey(node.cpv))[-1]:
+                                       "sys-apps/portage" == portage.cpv_getkey(node.cpv):
                                        portage_node = node
                                        asap_nodes.append(node)
                                        break
@@ -4073,6 +4064,7 @@ class depgraph(object):
                                print bold('*'+revision)
                                sys.stdout.write(text)
 
+               sys.stdout.flush()
                self.display_problems()
                return os.EX_OK
 
@@ -6641,8 +6633,8 @@ def action_depclean(settings, trees, ldpath_mtimes,
                        for cpv in reversed(pkgs):
                                metadata = dict(izip(metadata_keys,
                                        vardb.aux_get(cpv, metadata_keys)))
-                               if visible(settings, cpv, metadata,
-                                       built=True, installed=True):
+                               if visible(settings, Package(built=True, cpv=cpv,
+                                       installed=True, metadata=metadata, type_name="installed")):
                                        pkgs = [cpv]
                                        break
                        if len(pkgs) > 1:
index 2310ed84bfe5a1eca7d1eae239a545e8ef367df5..fa9012f7ff5b44881a0aa3c8f4648dc5558d45fa 100644 (file)
@@ -4356,6 +4356,7 @@ def _doebuild_exit_status_unlink(exit_status_file):
 
 _doebuild_manifest_exempt_depend = 0
 _doebuild_manifest_checked = None
+_doebuild_broken_manifests = set()
 
 def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
        fetchonly=0, cleanup=0, dbkey=None, use_cache=1, fetchall=0, tree=None,
@@ -4464,13 +4465,16 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                # Always verify the ebuild checksums before executing it.
                pkgdir = os.path.dirname(myebuild)
                manifest_path = os.path.join(pkgdir, "Manifest")
-               global _doebuild_manifest_checked
+               global _doebuild_manifest_checked, _doebuild_broken_manifests
+               if manifest_path in _doebuild_broken_manifests:
+                       return 1
                # Avoid checking the same Manifest several times in a row during a
                # regen with an empty cache.
                if _doebuild_manifest_checked != manifest_path:
                        if not os.path.exists(manifest_path):
                                writemsg("!!! Manifest file not found: '%s'\n" % manifest_path,
                                        noiselevel=-1)
+                               _doebuild_broken_manifests.add(manifest_path)
                                return 1
                        mf = Manifest(pkgdir, mysettings["DISTDIR"])
                        try:
@@ -4478,6 +4482,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        except portage.exception.FileNotFound, e:
                                writemsg("!!! A file listed in the Manifest " + \
                                        "could not be found: %s\n" % str(e), noiselevel=-1)
+                               _doebuild_broken_manifests.add(manifest_path)
                                return 1
                        except portage.exception.DigestException, e:
                                writemsg("!!! Digest verification failed:\n", noiselevel=-1)
@@ -4485,6 +4490,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                writemsg("!!! Reason: %s\n" % e.value[1], noiselevel=-1)
                                writemsg("!!! Got: %s\n" % e.value[2], noiselevel=-1)
                                writemsg("!!! Expected: %s\n" % e.value[3], noiselevel=-1)
+                               _doebuild_broken_manifests.add(manifest_path)
                                return 1
                        # Make sure that all of the ebuilds are actually listed in the
                        # Manifest.
@@ -4493,6 +4499,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                        writemsg("!!! A file is not listed in the " + \
                                        "Manifest: '%s'\n" % os.path.join(pkgdir, f),
                                        noiselevel=-1)
+                                       _doebuild_broken_manifests.add(manifest_path)
                                        return 1
                        _doebuild_manifest_checked = manifest_path
 
@@ -5422,8 +5429,9 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
                all_available = True
                versions = {}
                for atom in atoms:
-                       avail_pkg = best(mydbapi.match(atom))
+                       avail_pkg = mydbapi.match(atom)
                        if avail_pkg:
+                               avail_pkg = avail_pkg[-1] # highest (ascending order)
                                avail_slot = "%s:%s" % (dep_getkey(atom),
                                        mydbapi.aux_get(avail_pkg, ["SLOT"])[0])
                        elif not avail_pkg:
@@ -5431,8 +5439,9 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
                                if hasattr(mydbapi, "xmatch"):
                                        has_mask = bool(mydbapi.xmatch("match-all", atom))
                                if (selective or use_binaries or not has_mask):
-                                       avail_pkg = best(vardb.match(atom))
+                                       avail_pkg = vardb.match(atom)
                                        if avail_pkg:
+                                               avail_pkg = avail_pkg[-1] # highest (ascending order)
                                                avail_slot = "%s:%s" % (dep_getkey(atom),
                                                        vardb.aux_get(avail_pkg, ["SLOT"])[0])
                        if not avail_pkg:
index d634e816f8746ea0f340e88560c1bb5b715576fd..bd5e6b7fd14268136ce959a5e56a38f9335afe5c 100644 (file)
@@ -161,6 +161,7 @@ class binarytree(object):
                        self._pkgindex_default_pkg_data = {
                                "EAPI"    : eapi,
                                "IUSE"    : "",
+                               "LICENSE" : "",
                                "PROVIDE" : "",
                                "SLOT"    : "0",
                                "USE"     : ""