Attached patch adds a new function metascan() in portage.py and aliases it to portdbapi.metascan() and vardbapi.metascan(). It's basically the same code as in metalib.py (in private/genone/scripts), just mildly tweaked to work inside portage.py. It provides the core functionality for my metascan script which is now basically just a cli wrapper for the function.
Marius -- Public Key at http://www.genone.de/info/gpg-key.pub In the beginning, there was nothing. And God said, 'Let there be Light.' And there was still nothing, but you could see a bit better.
--- pym/portage.py 2005-11-13 14:55:16.000000000 +0100 +++ pym/portage.py 2005-12-09 18:39:44.000000000 +0100 @@ -4387,6 +4387,110 @@ return myslot +def __metascan_resolve_dep_strings(cpv, keys, values, mysettings): + result = values[:] + settings.setcpv(cpv) + for i in range(0, len(keys)): + if keys[i].find("DEPEND") >= 0 or keys[i] == "PROVIDE": + result[i] = " ".join(flatten(portage_dep.use_reduce(portage_dep.paren_reduce(values[i]), settings["USE"].split()))) + return result + +def __metascan_strip_atoms(keys, values, mysettings): + result = values[:] + for i in range(0, len(values)): + if keys[i] not in ["DEPEND", "RDEPEND", "PDEPEND", "CDEPEND", "PROVIDE"]: + continue + result[i] = "" + parts = values[i].split() + for x in parts: + if isvalidatom(x): + result[i] += dep_getkey(x) + else: + result[i] += x + result[i] += " " + result[i] = result[i].strip() + return result + +def metascan(db, keys, values, negated, mysettings, scanlist=None, operator="or", resolveDepStrings=False, stripAtoms=False, partial=False, regex=False, catlimit=None, debug=0, verbose=False): + """ + Function to find all packages matching certain metadata criteria. + """ + if len(keys) != len(values) or len(keys) != len(negated): + raise IndexError("argument length mismatch") + + if scanlist == None: + scanlist = {} + plist = db.cp_all() + for p in plist: + scanlist[p] = [] + for pv in db.cp_list(p): + scanlist[p].append(pv) + + resultlist = [] + + for p in scanlist: + if debug > 1: + sys.stderr.write("Scanning package %s\n" % p) + # check if we have a category restriction and if that's the case, skip this package if we don't have a match + if catlimit != None and catsplit(p)[0] not in catlimit: + if debug > 1: + sys.stderr.write("Skipping package %s from category %s due to category limit (%s)\n" % (p, catsplit(p)[0], str(catlimit))) + continue + for pv in scanlist[p]: + try: + result = [] + # this is the slow part, also generates noise if portage cache out of date + pvalues = db.aux_get(pv, keys) + + except KeyError: + sys.stderr.write("Error while scanning %s\n" % pv) + continue + + # save original values for debug + if debug > 1: + keys_uniq = [] + pvalues_orig = [] + for i in range(0, len(keys)): + if not keys[i] in keys_uniq: + keys_uniq.append(keys[i]) + pvalues_orig.append(pvalues[i]) + + # remove conditional deps whose coditions aren't met + if resolveDepStrings: + pvalues = __metascan_resolve_dep_strings(pv, keys, pvalues, settings) + + # we're only interested in the cat/pkg stuff from an atom here, so strip the rest + if stripAtoms: + pvalues = __metascan_strip_atoms(keys, pvalues, settings) + + # report also partial matches, e.g. "foo" in "foomatic" + if partial or regex: + for i in range(0, len(pvalues)): + result.append((partial and pvalues[i].find(values[i]) >= 0) \ + or (regex and bool(re.match(values[i], pvalues[i])))) + + # we're only interested in full matches in general + else: + result = [values[i] in pvalues[i].split() for i in range(0, len(pvalues))] + + # some funky logic operations to invert the adjust the match if negations were requested + result = [(negated[i] and not result[i]) or (not negated[i] and result[i]) for i in range(0, len(result))] + + # more logic stuff for conjunction or disjunction + if (operator == "or" and True in result) or (operator == "and" and not False in result): + if debug > 0: + sys.stderr.write("Match found: %s\n" % pv) + if debug > 1: + for i in range(0, len(keys_uniq)): + sys.stderr.write("%s from %s: %s\n" % (keys_uniq[i], pv, pvalues_orig[i])) + if verbose: + resultlist.append(pv) + else: + if not p in resultlist: + resultlist.append(p) + return resultlist + + class dbapi: def __init__(self): pass @@ -4867,6 +4971,7 @@ results[idx] = "0" return results + metascan = metascan class vartree(packagetree): "this tree will scan a var/db/pkg database located at root (passed to init)" @@ -5747,6 +5852,8 @@ newlist.append(mycpv) return newlist + metascan = metascan + class binarytree(packagetree): "this tree scans for a list of all packages available in PKGDIR" def __init__(self,root,pkgdir,virtual=None,clone=None):
signature.asc
Description: PGP signature