summaryrefslogtreecommitdiffstats
path: root/pym/portage_dep.py
diff options
context:
space:
mode:
authorMarius Mauch <genone@gentoo.org>2007-01-25 15:49:26 +0000
committerMarius Mauch <genone@gentoo.org>2007-01-25 15:49:26 +0000
commit3b08c21101b0801d7c5d6c145a27bef5cd42078c (patch)
tree2eea73b311d67b567410670630335796bf0a272c /pym/portage_dep.py
parentb4eed9540e19ee7038ac875f0e084f8256675580 (diff)
downloadportage-3b08c21101b0801d7c5d6c145a27bef5cd42078c.tar.gz
portage-3b08c21101b0801d7c5d6c145a27bef5cd42078c.tar.bz2
portage-3b08c21101b0801d7c5d6c145a27bef5cd42078c.zip
Namespace sanitizing, step 1
svn path=/main/trunk/; revision=5778
Diffstat (limited to 'pym/portage_dep.py')
l---------[-rw-r--r--]pym/portage_dep.py647
1 files changed, 1 insertions, 646 deletions
diff --git a/pym/portage_dep.py b/pym/portage_dep.py
index bf40452ac..e16bb2a7c 100644..120000
--- a/pym/portage_dep.py
+++ b/pym/portage_dep.py
@@ -1,646 +1 @@
-# deps.py -- Portage dependency resolution functions
-# Copyright 2003-2004 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Id$
-
-
-# DEPEND SYNTAX:
-#
-# 'use?' only affects the immediately following word!
-# Nesting is the only legal way to form multiple '[!]use?' requirements.
-#
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom.
-#
-# "a? z" -- If 'a' in [use], then b is valid.
-# "a? ( z )" -- Syntax with parenthesis.
-# "a? b? z" -- Deprecated.
-# "a? ( b? z )" -- Valid
-# "a? ( b? ( z ) ) -- Valid
-#
-
-import re, sys, types
-import portage_exception
-from portage_exception import InvalidData
-from portage_versions import catpkgsplit, catsplit, pkgcmp, pkgsplit, ververify
-
-def cpvequal(cpv1, cpv2):
- split1 = catpkgsplit(cpv1)
- split2 = catpkgsplit(cpv2)
-
- if not split1 or not split2:
- raise portage_exception.PortageException("Invalid data '%s, %s', parameter was not a CPV" % (cpv1, cpv2))
-
- if split1[0] != split2[0]:
- return False
-
- return (pkgcmp(split1[1:], split2[1:]) == 0)
-
-def strip_empty(myarr):
- """
- Strip all empty elements from an array
-
- @param myarr: The list of elements
- @type myarr: List
- @rtype: Array
- @return: The array with empty elements removed
- """
- for x in range(len(myarr)-1, -1, -1):
- if not myarr[x]:
- del myarr[x]
- return myarr
-
-def paren_reduce(mystr,tokenize=1):
- """
- Take a string and convert all paren enclosed entities into sublists, optionally
- futher splitting the list elements by spaces.
-
- Example usage:
- >>> paren_reduce('foobar foo ( bar baz )',1)
- ['foobar', 'foo', ['bar', 'baz']]
- >>> paren_reduce('foobar foo ( bar baz )',0)
- ['foobar foo ', [' bar baz ']]
-
- @param mystr: The string to reduce
- @type mystr: String
- @param tokenize: Split on spaces to produces further list breakdown
- @type tokenize: Integer
- @rtype: Array
- @return: The reduced string in an array
- """
- mylist = []
- while mystr:
- if ("(" not in mystr) and (")" not in mystr):
- freesec = mystr
- subsec = None
- tail = ""
- elif mystr[0] == ")":
- return [mylist,mystr[1:]]
- elif ("(" in mystr) and (mystr.index("(") < mystr.index(")")):
- freesec,subsec = mystr.split("(",1)
- subsec,tail = paren_reduce(subsec,tokenize)
- else:
- subsec,tail = mystr.split(")",1)
- if tokenize:
- subsec = strip_empty(subsec.split(" "))
- return [mylist+subsec,tail]
- return mylist+[subsec],tail
- mystr = tail
- if freesec:
- if tokenize:
- mylist = mylist + strip_empty(freesec.split(" "))
- else:
- mylist = mylist + [freesec]
- if subsec is not None:
- mylist = mylist + [subsec]
- return mylist
-
-def paren_enclose(mylist):
- """
- Convert a list to a string with sublists enclosed with parens.
-
- Example usage:
- >>> test = ['foobar','foo',['bar','baz']]
- >>> paren_enclose(test)
- 'foobar foo ( bar baz )'
-
- @param mylist: The list
- @type mylist: List
- @rtype: String
- @return: The paren enclosed string
- """
- mystrparts = []
- for x in mylist:
- if isinstance(x, list):
- mystrparts.append("( "+paren_enclose(x)+" )")
- else:
- mystrparts.append(x)
- return " ".join(mystrparts)
-
-# This is just for use by emerge so that it can enable a backward compatibility
-# mode in order to gracefully deal with installed packages that have invalid
-# atoms or dep syntax.
-_dep_check_strict = True
-
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
- """
- Takes a paren_reduce'd array and reduces the use? conditionals out
- leaving an array with subarrays
-
- @param deparray: paren_reduce'd list of deps
- @type deparray: List
- @param uselist: List of use flags
- @type uselist: List
- @param masklist: List of masked flags
- @type masklist: List
- @param matchall: Resolve all conditional deps unconditionally. Used by repoman
- @type matchall: Integer
- @rtype: List
- @return: The use reduced depend array
- """
- # Quick validity checks
- for x in range(len(deparray)):
- if deparray[x] in ["||","&&"]:
- if len(deparray) - 1 == x or not isinstance(deparray[x+1], list):
- raise portage_exception.InvalidDependString(deparray[x]+" missing atom list in \""+paren_enclose(deparray)+"\"")
- if deparray and deparray[-1] and deparray[-1][-1] == "?":
- raise portage_exception.InvalidDependString("Conditional without target in \""+paren_enclose(deparray)+"\"")
-
- global _dep_check_strict
-
- mydeparray = deparray[:]
- rlist = []
- while mydeparray:
- head = mydeparray.pop(0)
-
- if type(head) == types.ListType:
- additions = use_reduce(head, uselist, masklist, matchall, excludeall)
- if additions:
- rlist.append(additions)
- elif rlist and rlist[-1] == "||":
- #XXX: Currently some DEPEND strings have || lists without default atoms.
- # raise portage_exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"")
- rlist.append([])
-
- else:
- if head[-1] == "?": # Use reduce next group on fail.
- # Pull any other use conditions and the following atom or list into a separate array
- newdeparray = [head]
- while isinstance(newdeparray[-1], str) and newdeparray[-1][-1] == "?":
- if mydeparray:
- newdeparray.append(mydeparray.pop(0))
- else:
- raise ValueError, "Conditional with no target."
-
- # Deprecation checks
- warned = 0
- if len(newdeparray[-1]) == 0:
- sys.stderr.write("Note: Empty target in string. (Deprecated)\n")
- warned = 1
- if len(newdeparray) != 2:
- sys.stderr.write("Note: Nested use flags without parenthesis (Deprecated)\n")
- warned = 1
- if warned:
- sys.stderr.write(" --> "+" ".join(map(str,[head]+newdeparray))+"\n")
-
- # Check that each flag matches
- ismatch = True
- for head in newdeparray[:-1]:
- head = head[:-1]
- if head[0] == "!":
- head_key = head[1:]
- if not matchall and head_key in uselist or \
- head_key in excludeall:
- ismatch = False
- break
- elif head not in masklist:
- if not matchall and head not in uselist:
- ismatch = False
- break
- else:
- ismatch = False
-
- # If they all match, process the target
- if ismatch:
- target = newdeparray[-1]
- if isinstance(target, list):
- additions = use_reduce(target, uselist, masklist, matchall, excludeall)
- if additions:
- rlist.append(additions)
- elif not _dep_check_strict:
- # The old deprecated behavior.
- rlist.append(target)
- else:
- raise portage_exception.InvalidDependString(
- "Conditional without parenthesis: '%s?'" % head)
-
- else:
- rlist += [head]
-
- return rlist
-
-
-def dep_opconvert(deplist):
- """
- Iterate recursively through a list of deps, if the
- dep is a '||' or '&&' operator, combine it with the
- list of deps that follows..
-
- Example usage:
- >>> test = ["blah", "||", ["foo", "bar", "baz"]]
- >>> dep_opconvert(test)
- ['blah', ['||', 'foo', 'bar', 'baz']]
-
- @param deplist: A list of deps to format
- @type mydep: List
- @rtype: List
- @return:
- The new list with the new ordering
- """
-
- retlist = []
- x = 0
- while x != len(deplist):
- if isinstance(deplist[x], list):
- retlist.append(dep_opconvert(deplist[x]))
- elif deplist[x] == "||" or deplist[x] == "&&":
- retlist.append([deplist[x]] + dep_opconvert(deplist[x+1]))
- x += 1
- else:
- retlist.append(deplist[x])
- x += 1
- return retlist
-
-def get_operator(mydep):
- """
- Return the operator used in a depstring.
-
- Example usage:
- >>> from portage_dep import *
- >>> get_operator(">=test-1.0")
- '>='
-
- @param mydep: The dep string to check
- @type mydep: String
- @rtype: String
- @return: The operator. One of:
- '~', '=', '>', '<', '=*', '>=', or '<='
- """
- if mydep[0] == "~":
- operator = "~"
- elif mydep[0] == "=":
- if mydep[-1] == "*":
- operator = "=*"
- else:
- operator = "="
- elif mydep[0] in "><":
- if len(mydep) > 1 and mydep[1] == "=":
- operator = mydep[0:2]
- else:
- operator = mydep[0]
- else:
- operator = None
-
- return operator
-
-_dep_getcpv_cache = {}
-
-def dep_getcpv(mydep):
- """
- Return the category-package-version with any operators/slot specifications stripped off
-
- Example usage:
- >>> dep_getcpv('>=media-libs/test-3.0')
- 'media-libs/test-3.0'
-
- @param mydep: The depstring
- @type mydep: String
- @rtype: String
- @return: The depstring with the operator removed
- """
- global _dep_getcpv_cache
- retval = _dep_getcpv_cache.get(mydep, None)
- if retval is not None:
- return retval
- mydep_orig = mydep
- if mydep and mydep[0] == "*":
- mydep = mydep[1:]
- if mydep and mydep[-1] == "*":
- mydep = mydep[:-1]
- if mydep and mydep[0] == "!":
- mydep = mydep[1:]
- if mydep[:2] in [">=", "<="]:
- mydep = mydep[2:]
- elif mydep[:1] in "=<>~":
- mydep = mydep[1:]
- colon = mydep.rfind(":")
- if colon != -1:
- mydep = mydep[:colon]
- _dep_getcpv_cache[mydep_orig] = mydep
- return mydep
-
-def dep_getslot(mydep):
- """
- Retrieve the slot on a depend.
-
- Example usage:
- >>> dep_getslot('app-misc/test:3')
- '3'
-
- @param mydep: The depstring to retrieve the slot of
- @type mydep: String
- @rtype: String
- @return: The slot
- """
- colon = mydep.rfind(":")
- if colon != -1:
- return mydep[colon+1:]
- return None
-
-_invalid_atom_chars_regexp = re.compile("[()|?]")
-
-def isvalidatom(atom, allow_blockers=False):
- """
- Check to see if a depend atom is valid
-
- Example usage:
- >>> isvalidatom('media-libs/test-3.0')
- 0
- >>> isvalidatom('>=media-libs/test-3.0')
- 1
-
- @param atom: The depend atom to check against
- @type atom: String
- @rtype: Integer
- @return: One of the following:
- 1) 0 if the atom is invalid
- 2) 1 if the atom is valid
- """
- global _invalid_atom_chars_regexp
- if _invalid_atom_chars_regexp.search(atom):
- return 0
- if allow_blockers and atom.startswith("!"):
- atom = atom[1:]
- try:
- mycpv_cps = catpkgsplit(dep_getcpv(atom))
- except InvalidData:
- return 0
- operator = get_operator(atom)
- if operator:
- if operator[0] in "<>" and atom[-1] == "*":
- return 0
- if mycpv_cps and mycpv_cps[0] != "null":
- # >=cat/pkg-1.0
- return 1
- else:
- # >=cat/pkg or >=pkg-1.0 (no category)
- return 0
- if mycpv_cps:
- # cat/pkg-1.0
- return 0
-
- if (len(atom.split('/')) == 2):
- # cat/pkg
- return 1
- else:
- return 0
-
-def isjustname(mypkg):
- """
- Checks to see if the depstring is only the package name (no version parts)
-
- Example usage:
- >>> isjustname('media-libs/test-3.0')
- 0
- >>> isjustname('test')
- 1
- >>> isjustname('media-libs/test')
- 1
-
- @param mypkg: The package atom to check
- @param mypkg: String
- @rtype: Integer
- @return: One of the following:
- 1) 0 if the package string is not just the package name
- 2) 1 if it is
- """
- myparts = mypkg.split('-')
- for x in myparts:
- if ververify(x):
- return 0
- return 1
-
-iscache = {}
-
-def isspecific(mypkg):
- """
- Checks to see if a package is in category/package-version or package-version format,
- possibly returning a cached result.
-
- Example usage:
- >>> isspecific('media-libs/test')
- 0
- >>> isspecific('media-libs/test-3.0')
- 1
-
- @param mypkg: The package depstring to check against
- @type mypkg: String
- @rtype: Integer
- @return: One of the following:
- 1) 0 if the package string is not specific
- 2) 1 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
-
-def dep_getkey(mydep):
- """
- Return the category/package-name of a depstring.
-
- Example usage:
- >>> dep_getkey('media-libs/test-3.0')
- 'media-libs/test'
-
- @param mydep: The depstring to retrieve the category/package-name of
- @type mydep: String
- @rtype: String
- @return: The package category/package-version
- """
- mydep = dep_getcpv(mydep)
- if mydep and isspecific(mydep):
- mysplit = catpkgsplit(mydep)
- if not mysplit:
- return mydep
- return mysplit[0] + "/" + mysplit[1]
- else:
- return mydep
-
-def match_to_list(mypkg, mylist):
- """
- Searches list for entries that matches the package.
-
- @param mypkg: The package atom to match
- @type mypkg: String
- @param mylist: The list of package atoms to compare against
- @param mylist: List
- @rtype: List
- @return: A unique list of package atoms that match the given package atom
- """
- matches = []
- for x in mylist:
- if match_from_list(x, [mypkg]):
- if x not in matches:
- matches.append(x)
- return matches
-
-def best_match_to_list(mypkg, mylist):
- """
- Returns the most specific entry that matches the package given.
-
- @param mypkg: The package atom to check
- @type mypkg: String
- @param mylist: The list of package atoms to check against
- @type mylist: List
- @rtype: String
- @return: The package atom which best matches given the following ordering:
- - =cpv 6
- - ~cpv 5
- - =cpv* 4
- - cp:slot 3
- - >cpv 2
- - <cpv 2
- - >=cpv 2
- - <=cpv 2
- - cp 1
- """
- operator_values = {'=':6, '~':5, '=*':4,
- '>':2, '<':2, '>=':2, '<=':2, None:1}
- maxvalue = 0
- bestm = None
- for x in match_to_list(mypkg, mylist):
- if dep_getslot(x) is not None:
- if maxvalue < 3:
- maxvalue = 3
- bestm = x
- continue
- op_val = operator_values[get_operator(x)]
- if op_val > maxvalue:
- maxvalue = op_val
- bestm = x
- return bestm
-
-_match_from_list_cache = {}
-
-def match_from_list(mydep, candidate_list):
- """
- Searches list for entries that matches the package.
-
- @param mydep: The package atom to match
- @type mydep: String
- @param candidate_list: The list of package atoms to compare against
- @param candidate_list: List
- @rtype: List
- @return: A list of package atoms that match the given package atom
- """
-
- global _match_from_list_cache
- cache_key = (mydep, tuple(candidate_list))
- mylist = _match_from_list_cache.get(cache_key, None)
- if mylist is not None:
- return mylist[:]
-
- from portage_util import writemsg
- if mydep[0] == "!":
- mydep = mydep[1:]
-
- mycpv = dep_getcpv(mydep)
- mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific
- slot = None
-
- if not mycpv_cps:
- cat, pkg = catsplit(mycpv)
- ver = None
- rev = None
- slot = dep_getslot(mydep)
- else:
- cat, pkg, ver, rev = mycpv_cps
- if mydep == mycpv:
- raise KeyError("Specific key requires an operator" + \
- " (%s) (try adding an '=')" % (mydep))
-
- if ver and rev:
- operator = get_operator(mydep)
- if not operator:
- writemsg("!!! Invalid atom: %s\n" % mydep, noiselevel=-1)
- return []
- else:
- operator = None
-
- mylist = []
-
- if operator is None:
- for x in candidate_list:
- xs = pkgsplit(x)
- if xs is None:
- xcpv = dep_getcpv(x)
- if slot is not None:
- xslot = dep_getslot(x)
- if xslot is not None and xslot != slot:
- """ This function isn't given enough information to
- reject atoms based on slot unless *both* compared atoms
- specify slots."""
- continue
- if xcpv != mycpv:
- continue
- elif xs[0] != mycpv:
- continue
- mylist.append(x)
-
- elif operator == "=": # Exact match
- mylist = [cpv for cpv in candidate_list if cpvequal(cpv, mycpv)]
-
- elif operator == "=*": # glob match
- # XXX: Nasty special casing for leading zeros
- # Required as =* is a literal prefix match, so can't
- # use vercmp
- mysplit = catpkgsplit(mycpv)
- myver = mysplit[2].lstrip("0")
- if not myver or not myver[0].isdigit():
- myver = "0"+myver
- mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver
- for x in candidate_list:
- xs = catpkgsplit(x)
- myver = xs[2].lstrip("0")
- if not myver or not myver[0].isdigit():
- myver = "0"+myver
- xcpv = xs[0]+"/"+xs[1]+"-"+myver
- if xcpv.startswith(mycpv):
- mylist.append(x)
-
- elif operator == "~": # version, any revision, match
- for x in candidate_list:
- xs = catpkgsplit(x)
- if xs is None:
- raise InvalidData(x)
- if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]):
- continue
- if xs[2] != ver:
- continue
- mylist.append(x)
-
- elif operator in [">", ">=", "<", "<="]:
- mysplit = ["%s/%s" % (cat, pkg), ver, rev]
- for x in candidate_list:
- try:
- result = pkgcmp(pkgsplit(x), mysplit)
- except ValueError: # pkgcmp may return ValueError during int() conversion
- writemsg("\nInvalid package name: %s\n" % x, noiselevel=-1)
- raise
- if result is None:
- continue
- elif operator == ">":
- if result > 0:
- mylist.append(x)
- elif operator == ">=":
- if result >= 0:
- mylist.append(x)
- elif operator == "<":
- if result < 0:
- mylist.append(x)
- elif operator == "<=":
- if result <= 0:
- mylist.append(x)
- else:
- raise KeyError("Unknown operator: %s" % mydep)
- else:
- raise KeyError("Unknown operator: %s" % mydep)
-
- _match_from_list_cache[cache_key] = mylist
- return mylist
+portage/dep.py \ No newline at end of file