Currently vardbapi.aux_get only works for a subset of all auxdbkeys, as
some like KEYWORDS or DESCRIPTIOn aren't stored in vdb directly.
They are however stored in environment.bz2, but not accessible
there.
This is unintuitive and limits tools like equery or my own auxget
and metascan tools in their usability.

There are two solutions to this problem:
a) enhance vardbapi.aux_get so it can use environment.bz2
b) store more keys in vdb

Now there is a tradeoff to made: a) doesn't need space but is slow
while b) is fast but needs space, both in non-trivial amounts (runtime
increased from 1s to 9s for a metascan -i run and from 0.5s to 0.8s
for auxget -i, haven't actually checked the size increase, expect
somewhere between 1 and 10 megabytes on a typical install).

I'm attaching a patch that implements both (each in it's own hunk) as
well as a new emaint option to create the missing entries offline.

A not so obvious issue with a) is that due to the recent
storage optimizations (empty entries not being stored) it's worse than
I originally expected, as any entry missing a file will be looked up in
env.bz2 instead. Only way to avoid that would be to add special casing
in aux_get which I really dislike.

Opinions?

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.
--- /home/gentoo/svn/portage/main/trunk/bin/ebuild.sh	2006-01-08 04:30:16.000000000 +0100
+++ /usr/lib/portage/bin/ebuild.sh	2006-01-10 18:27:15.000000000 +0100
@@ -914,7 +914,8 @@
 	for f in ASFLAGS CATEGORY CBUILD CC CFLAGS CHOST CTARGET CXX \
 		CXXFLAGS DEPEND EXTRA_ECONF EXTRA_EINSTALL EXTRA_MAKE \
 		FEATURES INHERITED IUSE LDFLAGS LIBCFLAGS LIBCXXFLAGS \
-		LICENSE PDEPEND PF PKGUSE PROVIDE RDEPEND RESTRICT SLOT; do
+		LICENSE PDEPEND PF PKGUSE PROVIDE RDEPEND RESTRICT SLOT \
+		KEYWORDS HOMEPAGE SRC_URI DESCRIPTION; do
 		[ -n "${!f}" ] && echo $(echo "${!f}" | tr '\n,\r,\t' ' , , ' | sed s/'  \+'/' '/g) > ${f}
 	done
 	echo "${USE}"		> USE
--- /home/gentoo/svn/portage/main/trunk/pym/portage.py	2006-01-08 04:30:11.000000000 +0100
+++ /usr/lib/portage/pym/portage.py	2006-01-10 18:28:00.000000000 +0100
@@ -4501,17 +4477,32 @@
 	def aux_get(self, mycpv, wants):
 		global auxdbkeys
 		results = []
+		envlines = None
 		for x in wants:
-			myfn = self.root+VDB_PATH+"/"+str(mycpv)+"/"+str(x)
-			if os.access(myfn,os.R_OK):
-				myf = open(myfn, "r")
+			mydir = self.root+VDB_PATH+"/"+str(mycpv)+"/"
+			if os.access(mydir+str(x),os.R_OK):
+				myf = open(mydir+str(x), "r")
 				myd = myf.read()
 				myf.close()
-				myd = re.sub("[\n\r\t]+"," ",myd)
-				myd = re.sub(" +"," ",myd)
-				myd = string.strip(myd)
+			# Fallback to searching environment.bz2 if no key-specific file exists
+			elif os.access(mydir+"environment.bz2", os.R_OK):
+				if not envlines:
+					env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r")
+					envlines = env.read().split("\n")
+					env.close()
+				myd = [l for l in envlines if l.strip("\"\'").startswith(x+"=")]
+				if len(myd) > 1:
+					raise portage_exception.CorruptionError("multiple matches for "+x+" found in "+mydir+"environment.bz2")
+				elif len(myd) == 0:
+					myd = ""
+				else:
+					myd = myd[0].split("=",1)[1]
+					myd = myd.lstrip("$").strip("\'\"")
+					myd = re.sub("(\\\\[nrt])+", " ", myd)
 			else:
 				myd = ""
+			myd = re.sub("[\n\r\t]+"," ",myd)
+			myd = re.sub(" +"," ",myd)
+			myd = string.strip(myd)
 			results.append(myd)
 		if "EAPI" in wants:
 			idx = wants.index("EAPI")
--- /home/gentoo/svn/portage/main/trunk/bin/emaint	2006-01-08 04:30:16.000000000 +0100
+++ /usr/lib/portage/bin/emaint	2006-01-10 19:29:20.000000000 +0100
@@ -4,7 +4,7 @@
 from copy import copy
 from optparse import OptionParser, OptionValueError
 
-
+import re
 
 import os, portage, portage_const
 class WorldHandler(object):
@@ -44,8 +44,65 @@
 			errors.append(portage_const.WORLD_FILE + " could not be opened for writing")
 		return errors
 
+class VdbKeyHandler(object):
+	def name():
+		return "vdbkeys"
+	name = staticmethod(name)
+
+	def __init__(self):
+		self.list = portage.db["/"]["vartree"].dbapi.cpv_all()
+		self.missing = []
+		self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"]
+		
+		for p in self.list:
+			mydir = "/var/db/pkg/"+p
+			ismissing = True
+			for k in self.keys:
+				if os.path.exists(mydir+"/"+k):
+					ismissing = False
+					break
+			if ismissing:
+				self.missing.append(p)
+		
+	def check(self):
+		return ["%s has missing keys" % x for x in self.missing]
+	
+	def fix(self):
+	
+		errors = []
+	
+		for p in self.missing:
+			mydir = "/var/db/pkg/"+p
+			if not os.access(mydir+"/environment.bz2", os.R_OK):
+				errors.append("Can't access %s" % (mydir+"/environment.bz2"))
+			elif not os.access(mydir, os.W_OK):
+				errors.append("Can't create files in %s" % mydir)
+			else:
+				env = os.popen("bzip2 -dcq "+mydir+"/environment.bz2", "r")
+				envlines = env.read().split("\n")
+				env.close()
+				for k in self.keys:
+					s = [l for l in envlines if l.strip("\"\'").startswith(k+"=")]
+					if len(s) > 1:
+						errors.append("multiple matches for %s found in %s/environment.bz2" % (k, mydir))
+					elif len(s) == 0:
+						s = ""
+					else:
+						s = s[0].split("=",1)[1]
+						s = s.lstrip("$").strip("\'\"")
+						s = re.sub("(\\\\[nrt])+", " ", s)
+						s = re.sub("[\n\r\t]+"," ",s)
+						s = re.sub(" +"," ",s)
+						s = s.strip()
+						if s != "":
+							keyfile = open(mydir+"/"+k, "w")
+							keyfile.write(s+"\n")
+							keyfile.close()
+		
+		return errors
 
-modules = {"world" : WorldHandler}
+modules = {"world" : WorldHandler,
+		   "vdbkeys": VdbKeyHandler}
 
 
 module_names = modules.keys()

Attachment: signature.asc
Description: PGP signature

Reply via email to