Reverse index database and searching support.
--- a/src/client.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/client.py Thu Jul 19 14:30:15 2007 -0700
@@ -77,6 +77,7 @@
pkg uninstall pkg_fmri
pkg freeze [--version version_spec] [--release] [--branch] pkg_fmri
pkg unfreeze pkg_fmri
+ pkg search token
pkg image [--full|--partial|--user] dir
pkg image [-FPU] dir
@@ -202,6 +203,27 @@
return
+def search(config, image, args):
+ """Search through the reverse index databases for the given token."""
+
+ idxdir = os.path.join(image.imgdir, "index")
+
+ # Avoid enumerating any particular index directory, since some index
+ # databases may contain hundreds of thousands of keys. Any given key in
+ # an index, however, hopefully won't point to more than a few hundred
+ # packages.
+ results = [
+ (dir, link)
+ for dir in os.listdir(idxdir)
+ if os.path.isdir(os.path.join(idxdir, dir, args[0]))
+ for link in os.listdir(os.path.join(idxdir, dir, args[0]))
+ ]
+
+ for idx, link in results:
+ print idx, fmri.PkgFmri(urllib.unquote(link), None)
+
+ return
+
def create_image(config, args):
"""Create an image of the requested kind, at the given path."""
@@ -270,6 +292,8 @@
freeze(pcfg, icfg, pargs)
elif subcommand == "unfreeze":
unfreeze(pcfg, icfg, pargs)
+ elif subcommand == "search":
+ search(pcfg, icfg, pargs)
else:
print "pkg: unknown subcommand '%s'" % subcommand
usage()
--- a/src/modules/actions/driver.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/actions/driver.py Thu Jul 19 14:30:15 2007 -0700
@@ -104,3 +104,9 @@
def update_install(self, image):
# XXX This needs to run update_drv or something.
pass
+
+ def generate_indices(self):
+ return {
+ "driver_name": self.attrs["name"],
+ "driver_aliases": self.attrs["alias"]
+ }
--- a/src/modules/actions/file.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/actions/file.py Thu Jul 19 14:30:15 2007 -0700
@@ -84,3 +84,9 @@
def postinstall(self):
"""Client-side method that performs post-install actions."""
pass
+
+ def generate_indices(self):
+ return {
+ "content": self.hash,
+ "basename": os.path.basename(self.attrs["path"])
+ }
--- a/src/modules/actions/generic.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/actions/generic.py Thu Jul 19 14:30:15 2007 -0700
@@ -195,6 +195,37 @@
else:
return cmp(id(self), id(other))
+ def generate_indices(self):
+ """Generate for the reverse index database data for this action.
+
+ See pkg.client.pkgplan.make_indices for more information about
+ the reverse index database.
+
+ This method returns a dictionary mapping attribute names to
+ their values. This is not simply the action attribute
+ dictionary, 'attrs', as not necessarily all of these attributes
+ are interesting to look up, and there may be others which are
+ derived from the canonical attributes (like the path's basename).
+ """
+
+ indices = {}
+
+ # XXX What about derived indices -- those which aren't one of
+ # the attributes, such as basename? Just push computing them
+ # into the subclasses? Or is this simple enough that we have no
+ # need for a generic.generate_indices() that does anything
+ # interesting?
+ if hasattr(self, "reverse_indices"):
+ indices.update(
+ (idx, self.attrs[idx])
+ for idx in self.reverse_indices
+ )
+
+ if hasattr(self, "hash"):
+ indices["content"] = self.hash
+
+ return indices
+
def preinstall(self, image):
"""Client-side method that performs pre-install actions."""
pass
--- a/src/modules/client/image.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/client/image.py Thu Jul 19 14:30:15 2007 -0700
@@ -74,6 +74,9 @@
$IROOT/pkg
Directory containing manifests and states of installed packages.
+ $IROOT/index
+ Directory containing reverse-index databases.
+
XXX Root path probably can't be absolute, so that we can combine or
reuse Image contents.
@@ -130,6 +133,8 @@
os.makedirs(self.imgdir + "/file")
if not os.path.isdir(self.imgdir + "/pkg"):
os.makedirs(self.imgdir + "/pkg")
+ if not os.path.isdir(self.imgdir + "/index"):
+ os.makedirs(self.imgdir + "/index")
def set_attrs(self, type, root):
self.type = type
--- a/src/modules/client/imageplan.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/client/imageplan.py Thu Jul 19 14:30:15 2007 -0700
@@ -211,5 +211,8 @@
for p in self.pkg_plans:
p.postexecute()
+ for p in self.pkg_plans:
+ p.make_indices()
+
self.state = EXECUTED_OK
--- a/src/modules/client/pkgplan.py Tue Jul 17 12:50:06 2007 -0700
+++ b/src/modules/client/pkgplan.py Thu Jul 19 14:30:15 2007 -0700
@@ -23,6 +23,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+import errno
import os
import re
import urllib
@@ -130,3 +131,50 @@
self.destination_fmri.get_dir_path()), "w")
return
+
+ def make_indices(self):
+ """Create the reverse index databases for a particular package.
+
+ These are the databases mapping packaging object attribute
+ values back to their corresponding packages, allowing the
+ packaging system to look up a package based on, say, the
+ basename of a file that was installed.
+
+ XXX Need a method to remove what we put down here.
+ """
+
+ target = os.path.join("..", "..", "..", "pkg",
+ self.destination_fmri.get_dir_path())
+
+ gen = (
+ (k, v)
+ for action in self.actions
+ for k, v in action.generate_indices().iteritems()
+ )
+
+ for idx, val in gen:
+ idxdir = os.path.join(self.image.imgdir, "index", idx)
+
+ try:
+ os.makedirs(idxdir)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ if not isinstance(val, list):
+ val = [ val ]
+
+ for v in val:
+ dir = os.path.join(idxdir, v)
+
+ try:
+ os.makedirs(dir)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ link = os.path.join(dir,
+ self.destination_fmri.get_url_path())
+
+ if not os.path.lexists(link):
+ os.symlink(target, link)