From: Fabian Groffen Date: Sun, 13 Sep 2009 19:01:10 +0000 (-0000) Subject: Merged from trunk -r14209:14219 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=7cf510a8496f67c1a3648c4021ddff80e83a29b6;p=portage.git Merged from trunk -r14209:14219 | 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 | | | 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 | | | 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 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 | | | for this patch. | | 14217 | Reimplement isspecific() using a single regular expression | | zmedico | match. Thanks to Marat Radchenko | | | for this patch. | | 14218 | Fix false positives in gcc QA with debug mode some more. | | zmedico | Thanks again to Amit Dor-Shifer 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 | | | for this patch from bug #276813. | svn path=/main/branches/prefix/; revision=14244 --- diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index 4990a899d..63d82081b 100644 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -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 diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 274af0573..9a76a894a 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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" diff --git a/pym/portage/dep.py b/pym/portage/dep.py index 71dc758a5..df082eb70 100644 --- a/pym/portage/dep.py +++ b/pym/portage/dep.py @@ -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): """ diff --git a/pym/portage/tests/dep/test_isvalidatom.py b/pym/portage/tests/dep/test_isvalidatom.py index e74ec8ff5..9fa878e1f 100644 --- a/pym/portage/tests/dep/test_isvalidatom.py +++ b/pym/portage/tests/dep/test_isvalidatom.py @@ -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: diff --git a/pym/portage/versions.py b/pym/portage/versions.py index 00898a781..7d2e91eb1 100644 --- a/pym/portage/versions.py +++ b/pym/portage/versions.py @@ -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