Bug #334365 - Mask packages with invalid metadata as early as possible,
authorZac Medico <zmedico@gentoo.org>
Thu, 26 Aug 2010 03:12:13 +0000 (20:12 -0700)
committerZac Medico <zmedico@gentoo.org>
Thu, 26 Aug 2010 03:12:13 +0000 (20:12 -0700)
so that the depgraph won't select them unless they are already installed
and there is no other choice. This should trigger automatic reinstallation
of installed packages that have invalid metadata.

pym/_emerge/Package.py
pym/_emerge/depgraph.py

index 640f8bca1b821638f04da21796088f7d976fcf9b..557dda5c506e0a44ce3622ef0fb36e253c7d7a1d 100644 (file)
@@ -1,14 +1,15 @@
 # Copyright 1999-2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import re
 import sys
 from itertools import chain
 import portage
 from portage.cache.mappings import slot_dict_class
-from portage.dep import isvalidatom, use_reduce, \
+from portage.dep import Atom, isvalidatom, use_reduce, \
        paren_enclose, _slot_re
-from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
+from portage.eapi import eapi_has_src_uri_arrows, eapi_has_slot_deps, \
+       eapi_has_use_deps, eapi_has_strong_blocks, eapi_has_iuse_defaults, \
+       eapi_has_required_use, eapi_has_use_dep_defaults
 from _emerge.Task import Task
 
 if sys.hexversion >= 0x3000000:
@@ -33,6 +34,8 @@ class Package(Task):
                "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
                "_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
 
+       _dep_keys = ('DEPEND', 'PDEPEND', 'RDEPEND',)
+
        def __init__(self, **kwargs):
                Task.__init__(self, **kwargs)
                self.root = self.root_config.root
@@ -60,9 +63,66 @@ class Package(Task):
                self.category, self.pf = portage.catsplit(self.cpv)
                self.cpv_split = portage.catpkgsplit(self.cpv)
                self.pv_split = self.cpv_split[1:]
+               self._validate_deps()
                self.masks = self._masks()
                self.visible = self._visible(self.masks)
 
+       def _validate_deps(self):
+               """
+               Validate deps. This does not trigger USE calculation since that
+               is expensive for ebuilds and therefore we want to avoid doing
+               in unnecessarily (like for masked packages).
+               """
+               eapi = self.metadata['EAPI']
+               for k in self._dep_keys:
+                       v = self.metadata.get(k)
+                       if not v:
+                               continue
+                       try:
+                               atoms = portage.dep.use_reduce(v, matchall=True, flat=True,
+                                       is_valid_flag=self.iuse.is_valid_flag, token_class=Atom)
+                       except portage.exception.InvalidDependString as e:
+                               self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
+                       else:
+                               for atom in atoms:
+                                       if not isinstance(atom, Atom):
+                                               continue
+
+                                       if atom.slot and not eapi_has_slot_deps(eapi):
+                                               self._invalid_metadata('EAPI.incompatible',
+                                                       ("%s slot dependency" + \
+                                                       " not supported with EAPI='%s':" + \
+                                                       " '%s'") % (k, eapi, atom))
+
+                                       if atom.use and not eapi_has_use_deps(eapi):
+                                               self._invalid_metadata('EAPI.incompatible',
+                                                       ("%s use dependency" + \
+                                                       " not supported with EAPI='%s':" + \
+                                                       " '%s'") % (k, eapi, atom))
+
+                                       if atom.use and (atom.use.missing_enabled or atom.use.missing_disabled) and \
+                                               not eapi_has_use_dep_defaults(eapi):
+                                               self._invalid_metadata('EAPI.incompatible',
+                                                       ("%s use dependency" + \
+                                                       " not supported with EAPI='%s':" + \
+                                                       " '%s'") % (k, eapi, atom))
+
+                                       if atom.blocker and atom.blocker.overlap.forbid \
+                                               and not eapi_has_strong_blocks(eapi):
+                                               self._invalid_metadata('EAPI.incompatible',
+                                                       ("%s new blocker syntax" + \
+                                                       " not supported with EAPI='%s':" + \
+                                                       " '%s'") % (k, eapi, atom))
+
+               k = 'SRC_URI'
+               v = self.metadata.get(k)
+               if v:
+                       try:
+                               use_reduce(v, matchall=True, flat=True, is_src_uri=True,
+                                       allow_src_uri_file_renames=eapi_has_src_uri_arrows(eapi))
+                       except portage.exception.InvalidDependString as e:
+                               self._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
+
        def copy(self):
                return Package(built=self.built, cpv=self.cpv, depth=self.depth,
                        installed=self.installed, metadata=self._raw_metadata,
index d0d5386a142e93af1e621a5813306d3f9e3105ac..435cc1a981249a918e2e00c2be4b93e12bae659d 100644 (file)
@@ -1033,16 +1033,14 @@ class depgraph(object):
 
                                # TODO: For installed package, save any InvalidDependString
                                # info in dynamic_config and wait until display_problems()
-                               # to show it. For packages that aren't installed, we should
-                               # validate and mask them before they are selected.
+                               # to show it.
                                try:
                                        dep_string = portage.dep.use_reduce(dep_string,
                                                uselist=self._pkg_use_enabled(pkg), is_valid_flag=pkg.iuse.is_valid_flag)
                                except portage.exception.InvalidDependString as e:
                                        if not pkg.installed:
-                                               # TODO: validate and mask this before it's selected
-                                               show_invalid_depstring_notice(pkg, dep_string, str(e))
-                                               return 0
+                                               # should have been masked before it was selected
+                                               raise
                                        del e
 
                                        # Try again, but omit the is_valid_flag argument, since
@@ -1067,9 +1065,8 @@ class depgraph(object):
                                                del e
                                                continue
 
-                                       # TODO: validate and mask this before it's selected
-                                       show_invalid_depstring_notice(pkg, dep_string, str(e))
-                                       return 0
+                                       # should have been masked before it was selected
+                                       raise
 
                                if not dep_string:
                                        continue
@@ -1122,11 +1119,13 @@ class depgraph(object):
                                dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
                                strict=strict, priority=dep_priority)
                except portage.exception.InvalidDependString as e:
-                       show_invalid_depstring_notice(pkg, dep_string, str(e))
-                       del e
                        if pkg.installed:
+                               # TODO: show in display_problems()
+                               show_invalid_depstring_notice(pkg, dep_string, str(e))
                                return 1
-                       return 0
+
+                       # should have been masked before it was selected
+                       raise
 
                if debug:
                        writemsg_level("Candidates: %s\n" % \