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
