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):

Attachment: signature.asc
Description: PGP signature

Reply via email to