Merged from trunk -r14209:14219
authorFabian Groffen <grobian@gentoo.org>
Sun, 13 Sep 2009 19:01:10 +0000 (19:01 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sun, 13 Sep 2009 19:01:10 +0000 (19:01 -0000)
   | 14210   | In catpkgsplit(), use split('/', 1) since there should never |
   | zmedico | be more than on slash to split.                              |

   | 14211   | Optimize catpkgsplit() by creating a tuple directly instead  |
   | zmedico | of generating it from a list. Thanks to Marat Radchenko      |
   |         | <slonopotamusorama@gmail.com> for this patch.                |

   | 14212   | Bug #283795 - Make dep_check() filter out expanded indirect  |
   | zmedico | virual deps after they are no longer needed, in order to     |
   |         | avoid distortion of the depgraph.                            |

   | 14213   | Reimplement isvalidatom() to use a single regular expression |
   | zmedico | match. Thanks to Marat Radchenko <marat@slonopotamus.org>    |
   |         | for this patch from bug #276813.                             |

   | 14214   | In debug mode, avoid showing gcc QA search strings in the    |
   | zmedico | trace, so they won't trigger false positives. Thanks to Amit |
   |         | Dor-Shifer <amitds@oversi.com> for reporting.                |

   | 14215   | Fix code from previous commit so it's guaranteed to always   |
   | zmedico | properly reset debug state.                                  |

   | 14216   | Fix isvalidatom() to check the 'must not end in' clause from |
   | zmedico | PMS 2.1.2. Thanks to Marat Radchenko                         |
   |         | <marat@slonopotamus.org> for this patch.                     |

   | 14217   | Reimplement isspecific() using a single regular expression   |
   | zmedico | match. Thanks to Marat Radchenko <marat@slonopotamus.org>    |
   |         | for this patch.                                              |

   | 14218   | Fix false positives in gcc QA with debug mode some more.     |
   | zmedico | Thanks again to Amit Dor-Shifer <amitds@oversi.com> for      |
   |         | reporting.                                                   |

   | 14219   | simplify atom regex (winning even more performance) and      |
   | zmedico | turns it in verbose mode with comments. Added more corner    |
   |         | case tests. Thanks to Marat Radchenko                        |
   |         | <marat@slonopotamus.org> for this patch from bug #276813.    |

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

bin/misc-functions.sh
pym/portage/__init__.py
pym/portage/dep.py
pym/portage/tests/dep/test_isvalidatom.py
pym/portage/versions.py

index 4990a899df381b133bb9fcfb9a6bbdf4b773b5eb..63d82081b56c98668534abc27587a60f2a056643 100644 (file)
@@ -652,6 +652,13 @@ install_qa_check() {
 
        # Evaluate misc gcc warnings
        if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then
+               # In debug mode, this variable definition and corresponding grep calls
+               # will produce false positives if they're shown in the trace.
+               local reset_debug=0
+               if [[ ${-/x/} != $- ]] ; then
+                       set +x
+                       reset_debug=1
+               fi
                local m msgs=(
                        ": warning: dereferencing type-punned pointer will break strict-aliasing rules$"
                        ": warning: dereferencing pointer .* does break strict-aliasing rules$"
@@ -676,6 +683,7 @@ install_qa_check() {
                                abort="yes"
                        fi
                done
+               [[ $reset_debug = 1 ]] && set -x
                f=$(cat "${PORTAGE_LOG_FILE}" | \
                        "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py)
                if [[ -n ${f} ]] ; then
index 274af057366a9a10648132f3949b3c14c3a77a07..9a76a894a8aac88551afa4f48eb9da58aa977c5a 100644 (file)
@@ -7575,7 +7575,7 @@ def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/",
                                        "%s: %s '%s'" % (y[0], mycheck[1], depstring))
 
                        # pull in the new-style virtual
-                       mycheck[1].append(portage.dep.Atom("="+y[0]))
+                       mycheck[1].append(dep.Atom('=' + cpv))
                        a.append(mycheck[1])
                # Plain old-style virtuals.  New-style virtuals are preferred.
                if not pkgs:
@@ -7938,7 +7938,7 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
        writemsg("mysplit2: %s\n" % (mysplit2), 1)
 
        try:
-               myzaps = dep_zapdeps(mysplit, mysplit2, myroot,
+               selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
                        use_binaries=use_binaries, trees=trees)
        except portage.exception.InvalidAtom, e:
                if portage.dep._dep_check_strict:
@@ -7947,15 +7947,30 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
                # the dependencies of an installed package.
                return [0, _("Invalid atom: '%s'") % (e,)]
 
-       mylist = flatten(myzaps)
-       writemsg("myzaps:   %s\n" % (myzaps), 1)
-       writemsg("mylist:   %s\n" % (mylist), 1)
-       #remove duplicates
-       mydict={}
-       for x in mylist:
-               mydict[x]=1
-       writemsg("mydict:   %s\n" % (mydict), 1)
-       return [1,mydict.keys()]
+       # In order to optimize selection of virtual dependencies,
+       # _expand_new_virtuals() performs a lookahead on new-style
+       # virtuals, which causes expansion of indirect virtual deps.
+       # In order to avoid distorting the dependency graph, we want
+       # to discard the expanded indirect virtual deps after they
+       # are no longer needed, and return only the atom which
+       # corresponds to the virtual package which has been chosen
+       # to satisfy a direct dependency.
+       if ' ' not in depstring:
+               # The depgraph only passes in one virtual atom at at time
+               # here, since it delays evaluation of disjuctive deps.
+               try:
+                       virt_atom = dep.Atom(depstring)
+               except exception.InvalidAtom:
+                       pass
+               else:
+                       # Note: selected_atoms[-1] comes from the following line
+                       # inside _expand_new_virtuals():
+                       #   mycheck[1].append(dep.Atom('=' + cpv))
+                       if virt_atom.cp.startswith('virtual/') and \
+                               selected_atoms and selected_atoms[-1].cp == virt_atom.cp:
+                               selected_atoms = [selected_atoms[-1]]
+
+       return [1, selected_atoms]
 
 def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1):
        "Reduces the deplist to ones and zeros"
index 71dc758a5b94ea347e17ec379362c600d6707431..df082eb700fc0e8c488104dd460d28c03a2ba15e 100644 (file)
@@ -3,7 +3,6 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id$
 
-
 # DEPEND SYNTAX:
 #
 # 'use?' only affects the immediately following word!
@@ -24,7 +23,8 @@ from itertools import chain
 import portage.exception
 from portage.exception import InvalidData, InvalidAtom
 from portage.localization import _
-from portage.versions import catpkgsplit, catsplit, pkgcmp, pkgsplit, ververify
+from portage.versions import catpkgsplit, catsplit, \
+       pkgcmp, pkgsplit, ververify, _version
 import portage.cache.mappings
 
 def cpvequal(cpv1, cpv2):
@@ -309,7 +309,6 @@ def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
 
        return rlist
 
-
 def dep_opconvert(deplist):
        """
        Iterate recursively through a list of deps, if the
@@ -834,8 +833,40 @@ def dep_getusedeps( depend ):
                open_bracket = depend.find( '[', open_bracket+1 )
        return tuple(use_list)
 
-_valid_category = re.compile("^\w[\w-]*")
-_invalid_atom_chars_regexp = re.compile("[()|@]")
+# \w is [a-zA-Z0-9_]
+
+# 2.1.1 A category name may contain any of the characters [A-Za-z0-9+_.-].
+# It must not begin with a hyphen or a dot.
+_cat = r'[\w+][\w+.-]*'
+
+# 2.1.2 A package name may contain any of the characters [A-Za-z0-9+_-].
+# It must not begin with a hyphen,
+# and must not end in a hyphen followed by one or more digits.
+_pkg = \
+r'''([\w+](
+       -?                    # All other 2-char are handled by next
+       |[\w+]*               # No hyphens - no problems
+       |[\w+-]+(             # String with a hyphen...
+               [A-Za-z+_-]       # ... must end in nondigit
+               |[A-Za-z+_][\w+]+ # ... or in nondigit and then nonhyphens
+       )
+))'''
+
+# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-].
+# It must not begin with a hyphen or a dot.
+_slot = r'(:[\w+][\w+.-]*)?'
+
+_use = r'(\[.*\])?'
+_op = r'([=~]|[><]=?)'
+_cp = _cat + '/' + _pkg
+_cpv = _cp + '-' + _version
+
+_cpv_re = re.compile('^' + _cpv + '$', re.VERBOSE)
+_atom_re = re.compile(r'^(' +
+       '(' + _op + _cpv + _slot + _use + ')|' +
+       '(=' + _cpv + r'\*' + _slot + _use + ')|' +
+       '(' + _cp + _slot + _use + ')' +
+       ')$', re.VERBOSE)
 
 def isvalidatom(atom, allow_blockers=False):
        """
@@ -843,85 +874,38 @@ def isvalidatom(atom, allow_blockers=False):
 
        Example usage:
                >>> isvalidatom('media-libs/test-3.0')
-               0
+               False
                >>> isvalidatom('>=media-libs/test-3.0')
-               1
+               True
 
        @param atom: The depend atom to check against
-       @type atom: String
-       @rtype: Integer
+       @type atom: String or Atom
+       @rtype: Boolean
        @return: One of the following:
-               1) 0 if the atom is invalid
-               2) 1 if the atom is valid
+               1) False if the atom is invalid
+               2) True if the atom is valid
        """
        existing_atom = Atom._atoms.get(atom)
        if existing_atom is not None:
                atom = existing_atom
        if isinstance(atom, Atom):
-               if atom.blocker and not allow_blockers:
-                       return 0
-               return 1
-       global _invalid_atom_chars_regexp
-       if _invalid_atom_chars_regexp.search(atom):
-               return 0
-       if allow_blockers and atom[:1] == "!":
-               if atom[1:2] == "!":
+               return allow_blockers or not atom.blocker
+       if len(atom) < 2:
+               return False
+       if allow_blockers and atom[0] == '!':
+               if atom[1] == '!':
                        atom = atom[2:]
                else:
                        atom = atom[1:]
-
-       if dep_getslot(atom) == "":
-               # empty slot is invalid (None is valid)
-               return 0
-
+       if _atom_re.match(atom) is None:
+               return False
        try:
                use = dep_getusedeps(atom)
                if use:
                        use = _use_dep(use)
+               return True
        except InvalidAtom:
-               return 0
-
-       cpv = dep_getcpv(atom)
-       cpv_catsplit = catsplit(cpv)
-       without_slot = remove_slot(atom)
-       mycpv_cps = None
-       if cpv:
-               if len(cpv_catsplit) == 2:
-                       if _valid_category.match(cpv_catsplit[0]) is None:
-                               return 0
-                       if cpv_catsplit[0] == "null":
-                               # "null" category is valid, missing category is not.
-                               mycpv_cps = catpkgsplit(cpv.replace("null/", "cat/", 1))
-                               if mycpv_cps:
-                                       mycpv_cps = list(mycpv_cps)
-                                       mycpv_cps[0] = "null"
-               if not mycpv_cps:
-                       mycpv_cps = catpkgsplit(cpv)
-               if mycpv_cps is None and cpv != without_slot:
-                       return 0
-
-       operator = get_operator(atom)
-       if operator:
-               if operator[0] in "<>" and without_slot[-1:] == "*":
-                       return 0
-               if mycpv_cps:
-                       if len(cpv_catsplit) == 2:
-                               # >=cat/pkg-1.0
-                               return 1
-                       else:
-                               return 0
-               else:
-                       # >=cat/pkg or >=pkg-1.0 (no category)
-                       return 0
-       if mycpv_cps:
-               # cat/pkg-1.0
-               return 0
-
-       if len(cpv_catsplit) == 2:
-               # cat/pkg
-               return 1
-       else:
-               return 0
+               return False
 
 def isjustname(mypkg):
        """
@@ -957,27 +941,24 @@ def isspecific(mypkg):
 
        Example usage:
                >>> isspecific('media-libs/test')
-               0
+               False
                >>> isspecific('media-libs/test-3.0')
-               1
+               True
 
        @param mypkg: The package depstring to check against
        @type mypkg: String
-       @rtype: Integer
+       @rtype: Boolean
        @return: One of the following:
-               1) 0 if the package string is not specific
-               2) 1 if it is
+               1) False if the package string is not specific
+               2) True if it is
        """
        try:
                return iscache[mypkg]
        except KeyError:
                pass
-       mysplit = mypkg.split("/")
-       if not isjustname(mysplit[-1]):
-                       iscache[mypkg] = 1
-                       return 1
-       iscache[mypkg] = 0
-       return 0
+       retval = _cpv_re.match(mypkg) is not None
+       iscache[mypkg] = retval
+       return retval
 
 def dep_getkey(mydep):
        """
index e74ec8ff529b057ce7d714daafd33a4d7e468912..9fa878e1f295d7e202cb913517d7237a61f07e3b 100644 (file)
@@ -62,13 +62,25 @@ class IsValidAtom(TestCase):
                          ( ">=null/portage-2.1", True ),
                          ( "~null/portage-2.1", True ),
                          ( "=null/portage-2.1*", True ),
-                         ( "=foo/bar-123-1", True ),
-                         ( "=foo/bar-123-1-r1", True ),
+
+                       # These are invalid because pkg name must not end in hyphen
+                       # followed by numbers
+                         ( "=foo/bar-123-1", False ),
+                         ( "=foo/bar-123-1-r1", False ),
+                         ( "foo/bar-1", False ),
+
                          ( "=foo/bar--baz-1-r1", True ),
                          ( "=foo/bar-baz--1-r1", True ),
                          ( "=foo/bar-baz---1-r1", True ),
                          ( "=foo/bar-baz---1", True ),
                          ( "=foo/bar-baz-1--r1", False ),
+                         ( "games-strategy/ufo2000", True ),
+                         ( "~games-strategy/ufo2000-0.1", True ),
+                         ( "=media-libs/x264-20060810", True ),
+                         ( "foo/b", True ),
+                         ( "app-text/7plus", True ),
+                         ( "foo/666", True ),
+                         ( "=dev-libs/poppler-qt3-0.11*", True ),
                ]
 
                for test in tests:
index 00898a78167a3b69f9f3c4b808020e2a2a7b66f9..7d2e91eb14ab355d0d22069dd0f1a09c555eee2c 100644 (file)
@@ -5,8 +5,10 @@
 
 import re
 
-# PREFIX hack: -r(\\d+) -> -r(\\d+|0\\d+\\.\\d+) (see below)
-ver_regexp = re.compile("^(cvs\\.)?(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+|0\\d+\\.\\d+))?$")
+# PREFIX hack: -r(\d+) -> -r(\d+|0\d+\.\d+) (see below)
+_version = r'(cvs\.)?(\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)(-r(\d+|0\d+\.\d+))?'
+
+ver_regexp = re.compile("^" + _version + "$")
 suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
 suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
 endversion_keys = ["pre", "p", "alpha", "beta", "rc"]
@@ -295,19 +297,18 @@ def catpkgsplit(mydata,silent=1):
                return catcache[mydata]
        except KeyError:
                pass
-       mysplit=mydata.split("/")
+       mysplit = mydata.split('/', 1)
        p_split=None
        if len(mysplit)==1:
-               retval=["null"]
+               cat = "null"
                p_split=pkgsplit(mydata,silent=silent)
        elif len(mysplit)==2:
-               retval=[mysplit[0]]
+               cat = mysplit[0]
                p_split=pkgsplit(mysplit[1],silent=silent)
        if not p_split:
                catcache[mydata]=None
                return None
-       retval.extend(p_split)
-       retval = tuple(retval)
+       retval = (cat, p_split[0], p_split[1], p_split[2])
        catcache[mydata]=retval
        return retval