-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This patch should cover the backport of 3.0's plugin framework.  Mostly
needed to backport a few utils, which were stuck in portage_util.py.  A
few extra files ( portage_plugins and portage_modules ) were taken
wholesale.  Also a small addition to portage_data and portage_const was
needed.  After applying the patch, register_plugins.py needs an execute
bit to run ;)

Please test these as well.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iQIVAwUBQ3q8DWzglR5RwbyYAQK1Hw/+Lod7ufd+TdSvTlFz2ehhUEewfW3uvJ11
5MVFS0scOfgmKpZOlCd8UzkJS6/Stiuyr3dC+EEw1YnGDbr2Luvv2y7l1JUVrm0M
ogBBDb0MtFvurDg/S0fAAS91L3U5xHyC3R52MslTzwhsasjXq7oHWSxZVgN+nAvW
zmOGHj5+GMtDTvd34RgdXZbM7Ja6slvBZwYYYLWKcqC3pTKpIMIUUNZ7OUuol1Wa
6RCpHklvVMUA4ooGJHJkM/E9BvMLp0p1VufHyznoX1bo2yvQSR6lEYeSlnFIEm/X
ZirjieZPSbSxDZsz6SwJLa/YOOXou0lYZAn4ZRjTJ2HwrUewUdxirGKbyFriNGXe
VF1ZKvTIBNvu17CmwxGDi2esdllW3pha4ioStIYfrvp9ZR5R74R6tUSNPSIIV0CZ
XxleA4RRjAo5OyXHfoOr9N2dlEHVQ3F+BOWZwAlAkd3R3EdVcFhIeCTv8Wi6xuhp
sl5++d+Cj8YnX/bqZlHbWm8loSjZ2gJlXvBcdjGTsvwXQbZw48l31B++HqTUIfTP
NpZvS35QGvB0hVvTiHE7BkcRaZum/gFnSEnqUC6qMUWfffAJROmlaiUrvmjiT0Yc
IUDloJzmwUeUGm2w0JwQ8RqezMSe4jFEq3k7LNw4vDoE43UDdrdniD84tY/zCWPg
04Ssv5ecSbU=
=vXbb
-----END PGP SIGNATURE-----
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/bin/register_plugin.py ./bin/register_plugin.py
--- /usr/lib/portage/bin/register_plugin.py     1969-12-31 19:00:00.000000000 
-0500
+++ ./bin/register_plugin.py    2005-11-15 23:13:04.961017280 -0500
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring ([EMAIL PROTECTED])
+# License: GPL2
+# $Id:$
+
+import portage_plugins
+from portage_modules import load_attribute
+import sys
+
+def set(ptype, magic, version, namespace):
+       load_attribute(namespace)
+       # loaded.
+       portage.plugins.register(ptype, magic, version, namespace, replace=True)
+
+def cleanse(ptype, magic, version):
+       portage.plugins.deregister(ptype, magic, version)
+       
+def get_list(ptype=None):
+       return portage.plugins.query_plugins(ptype)
+
+if __name__ == "__main__":
+       args = sys.argv[1:]
+       ret = 0
+       if "-l" in args:
+               args.pop(args.index("-l"))
+               if len(args) == 0:
+                       args = [None]
+               for x in args:
+                       print "querying %s" % str(x)
+                       try:
+                               i = get_list(x).items()
+                               if x is not None:
+                                       i = [(x, dict(i))]
+                               for k,v in i:
+                                       print
+                                       try:
+                                               l = max(map(lambda y: len(y), 
v.keys())) + 4
+                                               print "%s => " % k
+                                               for y in v.keys():
+                                                       print "%s:    %s, %s" % 
(y.rjust(l), v[y]["namespace"], v[y]["version"])
+                                       except ValueError:
+                                               print "%s => no plugins found" 
% k
+                               print
+                       except Exception, e:
+                               print "caught exception %s querying" % e
+                               ret = 1
+       elif "-s" in args:
+               args.pop(args.index("-s"))
+               if len(args) != 4:
+                       print "need 4 args- ptype magic version namespace"
+                       sys.exit(1)
+               print "registering namespace(%s) as type(%s) constant(%s), 
ver(%s)" % (args[3], args[0], args[1], args[2])
+               set(*args)
+       elif "-r" in args:
+               args.pop(args.index("-r"))
+               if len(args) != 3:
+                       print "need 3 args- ptype magic version"
+                       sys.exit(1)
+               print "deregistering type(%s) constant(%s) ver(%s)" % (args[0], 
args[1], args[2])
+               cleanse(*args)
+       elif "-p" in args:
+               args.pop(args.index("-p"))
+               if len(args) != 0:
+                       print "no args allowed currently"
+                       sys.exit(1)
+               for ptype, v in get_list(None).iteritems():
+                       for magic, vals in v.iteritems():
+                               print "%s -s %s %s %s %s" % (sys.argv[0], 
ptype, magic, vals["version"], vals["namespace"])
+       else:
+               if "--help" not in args:
+                       print "command required"
+               print
+               print "options available: -s, -r, -l"
+               print "-s ptype magic ver namespace"
+               print "-r ptype magic ver"
+               print "-l [ptype]"
+               print
+               if "--help" not in args:
+                       sys.exit(1)
+       sys.exit(0)
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_const.py ./pym/portage_const.py
--- /usr/lib/portage/pym/portage_const.py       2005-11-15 23:52:28.952635928 
-0500
+++ ./pym/portage_const.py      2005-11-15 23:25:01.630067024 -0500
@@ -44,6 +44,7 @@
 
STICKIES=["KEYWORDS_ACCEPT","USE","CFLAGS","CXXFLAGS","MAKEOPTS","EXTRA_ECONF","EXTRA_EINSTALL","EXTRA_EMAKE"]
 
 EAPI = 0
+PLUGINS_DIR            = "/var/lib/portage/plugins"
 
 # ===========================================================================
 # END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANT
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_data.py ./pym/portage_data.py
--- /usr/lib/portage/pym/portage_data.py        2005-11-15 23:42:34.000000000 
-0500
+++ ./pym/portage_data.py       2005-11-15 23:53:05.503079416 -0500
@@ -43,6 +43,7 @@
 
 uid=os.getuid()
 wheelgid=0
+root_uid=0
 
 if uid==0:
        secpass=2
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_dep_mod.py ./pym/portage_dep_mod.py
--- /usr/lib/portage/pym/portage_dep_mod.py     2005-11-15 23:52:28.954635624 
-0500
+++ ./pym/portage_dep_mod.py    1969-12-31 19:00:00.000000000 -0500
@@ -1,151 +0,0 @@
-# deps.py -- Portage dependency resolution functions
-# Copyright 2003-2004 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-src/portage/pym/portage_dep.py,v 1.15.2.3 
2005/04/02 14:07:59 jstubbs Exp $
-cvs_id_string="$Id: portage_dep.py,v 1.15.2.3 2005/04/02 14:07:59 jstubbs Exp 
$"[5:-2]
-
-# DEPEND SYNTAX:
-#
-# 'use?' only affects the immediately following word!
-# Nesting is the only legal way to form multiple '[!]use?' requirements.
-#
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom.
-#
-# "a? z"           -- If 'a' in [use], then b is valid.
-# "a? ( z )"       -- Syntax with parenthesis.
-# "a? b? z"        -- Deprecated.
-# "a? ( b? z )"    -- Valid
-# "a? ( b? ( z ) ) -- Valid
-#
-
-import os,string,types,sys,copy
-import portage_exception
-
-def strip_empty(myarr):
-       for x in range(len(myarr)-1, -1, -1):
-               if not myarr[x]:
-                       del myarr[x]
-       return myarr
-
-def paren_reduce(mystr,tokenize=1):
-       "Accepts a list of strings, and converts '(' and ')' surrounded items 
to sub-lists"
-       mylist = []
-       while mystr:
-               if ("(" not in mystr) and (")" not in mystr):
-                       freesec = mystr
-                       subsec = None
-                       tail = ""
-               elif mystr[0] == ")":
-                       return [mylist,mystr[1:]]
-               elif ("(" in mystr) and (mystr.index("(") < mystr.index(")")):
-                       freesec,subsec = mystr.split("(",1)
-                       subsec,tail = paren_reduce(subsec,tokenize)
-               else:
-                       subsec,tail = mystr.split(")",1)
-                       if tokenize:
-                               subsec = strip_empty(subsec.split(" "))
-                               return [mylist+subsec,tail]
-                       return mylist+[subsec],tail
-               mystr = tail
-               if freesec:
-                       if tokenize:
-                               mylist = mylist + strip_empty(freesec.split(" 
"))
-                       else:
-                               mylist = mylist + [freesec]
-               if subsec is not None:
-                       mylist = mylist + [subsec]
-       return mylist
-
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
-       """Takes a paren_reduce'd array and reduces the use? conditionals out
-       leaving an array with subarrays
-       """
-       # Quick validity checks
-       for x in range(1,len(deparray)):
-               if deparray[x] in ["||","&&"]:
-                       if len(deparray) == x:
-                               # Operator is the last element
-                               raise 
portage_exception.InvalidDependString("INVALID "+deparray[x]+" DEPEND STRING: 
"+str(deparray))
-                       if type(deparray[x+1]) != types.ListType:
-                               # Operator is not followed by a list
-                               raise 
portage_exception.InvalidDependString("INVALID "+deparray[x]+" DEPEND STRING: 
"+str(deparray))
-       if deparray and deparray[-1] and deparray[-1][-1] == "?":
-               # Conditional with no target
-               raise portage_exception.InvalidDependString("INVALID 
"+deparray[x]+" DEPEND STRING: "+str(deparray))
-       
-       mydeparray = deparray[:]
-       rlist = []
-       while mydeparray:
-               head = mydeparray.pop(0)
-
-               if type(head) == types.ListType:
-                       rlist = rlist + [use_reduce(head, uselist, masklist, 
matchall, excludeall)]
-
-               else:
-                       if head[-1] == "?": # Use reduce next group on fail.
-                               # Pull any other use conditions and the 
following atom or list into a separate array
-                               newdeparray = [head]
-                               while isinstance(newdeparray[-1], str) and 
newdeparray[-1][-1] == "?":
-                                       if mydeparray:
-                                               
newdeparray.append(mydeparray.pop(0))
-                                       else:
-                                               raise ValueError, "Conditional 
with no target."
-
-                               # Deprecation checks
-                               warned = 0
-                               if len(newdeparray[-1]) == 0:
-                                       sys.stderr.write("Note: Empty target in 
string. (Deprecated)\n")
-                                       warned = 1
-                               if len(newdeparray) != 2:
-                                       sys.stderr.write("Note: Nested use 
flags without parenthesis (Deprecated)\n")
-                                       warned = 1
-                               if warned:
-                                       sys.stderr.write("  --> 
"+string.join(map(str,[head]+newdeparray))+"\n")
-
-                               # Check that each flag matches
-                               ismatch = True
-                               for head in newdeparray[:-1]:
-                                       head = head[:-1]
-                                       if head[0] == "!":
-                                               head = head[1:]
-                                               if not matchall and head in 
uselist or head in excludeall:
-                                                       ismatch = False
-                                                       break
-                                       elif head not in masklist:
-                                               if not matchall and head not in 
uselist:
-                                                       ismatch = False
-                                                       break
-                                       else:
-                                               ismatch = False
-
-                               # If they all match, process the target
-                               if ismatch:
-                                       target = newdeparray[-1]
-                                       if isinstance(target, list):
-                                               rlist += [use_reduce(target, 
uselist, masklist, matchall, excludeall)]
-                                       else:
-                                               rlist += [target]
-
-                       else:
-                               rlist += [head]
-
-       return rlist
-
-
-def dep_opconvert(deplist):
-       """Move || and && to the beginning of the following arrays"""
-       # Hack in management of the weird || for dep_wordreduce, etc.
-       # dep_opconvert: [stuff, ["||", list, of, things]]
-       # At this point: [stuff, "||", [list, of, things]]
-       retlist = []
-       x = 0
-       while x != len(deplist):
-               if isinstance(deplist[x], list):
-                       retlist.append(dep_opconvert(deplist[x]))
-               elif deplist[x] == "||" or deplist[x] == "&&":
-                       retlist.append([deplist[x]] + 
dep_opconvert(deplist[x+1]))
-                       x += 1
-               else:
-                       retlist.append(deplist[x])
-               x += 1
-       return retlist
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_file.py ./pym/portage_file.py
--- /usr/lib/portage/pym/portage_file.py        2005-11-15 23:52:28.955635472 
-0500
+++ ./pym/portage_file.py       2005-11-15 23:20:52.424951960 -0500
@@ -8,6 +8,7 @@
 import portage_data
 import portage_exception
 from portage_localization import _
+import stat
 
 def normpath(mypath):
        newpath = os.path.normpath(mypath)
@@ -48,15 +49,78 @@
                                        os.umask(old_umask)
                                        raise
                                portage_util.writemsg(_("Failed to chown: 
%(path)s to %(uid)s:%(gid)s\n") % {"path":mypath,"uid":uid,"gid":gid})
-
        os.umask(old_umask)
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
+
+def ensure_dirs(path, gid=-1, uid=-1, mode=0777, minimal=False):
+       """ensure dirs exist, creating as needed with (optional) gid, uid, and 
mode
+       be forewarned- if mode is specified to a mode that blocks the euid from 
accessing the dir, this 
+       code *will* try to create the dir"""
+
+       try:
+               st = os.stat(path)
+       except OSError:
+               base = os.path.sep
+               try:
+                       um = os.umask(0)
+                       # if the dir perms would lack +wx, we have to force it
+                       force_temp_perms = ((mode & 0300) != 0300)
+                       resets = []
+                       apath = normpath(os.path.abspath(path))
+                       sticky_parent = False
+                       creating = False
+                       
+                       for dir in apath.split(os.path.sep):
+                               base = os.path.join(base,dir)
+                               try:
+                                       st = os.stat(base)
+                                       # something exists.  why are we doing 
isdir?
+                                       if not stat.S_ISDIR(st.st_mode):
+                                               return False
+                                       
+                                       # if it's a subdir, we need +wx at least
+                                       if apath != base:
+                                               if ((st.st_mode & 0300) != 
0300):
+                                                       try:                    
os.chmod(base, (st.st_mode | 0300))
+                                                       except OSError: return 
False
+                                                       resets.append((base, 
st.st_mode))
+                                               sticky_parent = (st.st_gid & 
stat.S_ISGID)
+
+                               except OSError:
+                                       # nothing exists.
+                                       try:
+                                               if force_temp_perms:
+                                                       os.mkdir(base, 0700)
+                                                       resets.append((base, 
mode))
+                                               else:
+                                                       os.mkdir(base, mode)
+                                                       if base == apath and 
sticky_parent:
+                                                               
resets.append((base, mode))
+                                                       if gid != -1 or uid != 
-1:
+                                                               os.chown(base, 
uid, gid)
+                                       except OSError:
+                                               return False
+
+                       try:
+                               for base, m in reversed(resets):
+                                       os.chmod(base, m)
+                               if uid != -1 or gid != -1:
+                                       os.chown(base, uid, gid)
+                       except OSError:
+                               return False
+               
+               finally:
+                       os.umask(um)
+               return True
+       else:
+               try:
+                       if (gid != -1 and gid != st.st_gid) or (uid != -1 and 
uid != st.st_uid):
+                               os.chown(path, uid, gid)
+                       if minimal:
+                               if mode != (st.st_mode & mode):
+                                       os.chmod(path, st.st_mode | mode)
+                       elif mode != (st.st_mode & 07777):
+                               os.chmod(path, mode)
+               except OSError:
+                       return False
+       return True
+
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_locks.py ./pym/portage_locks.py
--- /usr/lib/portage/pym/portage_locks.py       2005-11-15 23:52:28.955635472 
-0500
+++ ./pym/portage_locks.py      2005-11-15 23:21:13.581735640 -0500
@@ -11,6 +11,7 @@
 import string
 import time
 import types
+import fcntl
 import portage_exception
 import portage_file
 import portage_util
@@ -358,3 +359,91 @@
 
        return results
 
+class LockException(Exception):
+       """Base lock exception class"""
+       def __init__(self, path, reason):
+               self.path, self.reason = path, reason
+               
+class NonExistant(LockException):
+       """Missing file/dir exception"""
+       def __init__(self, path, reason=None):
+               LockException.__init__(self, path, reason)
+       def __str__(self):
+               return "Lock action for '%s' failed due to not being a valid 
dir/file %s" % (self.path, self.reason)
+
+class GenericFailed(LockException):
+       """the fallback lock exception class- covers perms, IOError's, and 
general whackyness"""
+       def __str__(self):
+               return "Lock action for '%s' failed due to '%s'" % (self.path, 
self.reason)
+
+
+# should the fd be left open indefinitely?
+# IMO, it shouldn't, but opening/closing everytime around is expensive
+
+class FsLock(object):
+       __slots__ = ["path", "fd", "create"]
+       def __init__(self, path, create=False):
+               """path specifies the fs path for the lock
+               create controls whether the file will be create if the file 
doesn't exist
+               if create is true, the base dir must exist, and it will create 
a file
+               
+               If you want a directory yourself, create it.
+               """
+               self.path = path
+               self.fd = None
+               self.create = create
+               if not create:
+                       if not os.path.exists(path):
+                               raise NonExistant(path)
+
+       def _acquire_fd(self):
+               if self.create:
+                       try:    self.fd = os.open(self.path, os.R_OK|os.O_CREAT)
+                       except OSError, oe:
+                               raise GenericFailed(self.path, oe)
+               else:
+                       try:    self.fd = os.open(self.path, os.R_OK)
+                       except OSError, oe:     raise NonExistant(self.path, oe)
+       
+       def _enact_change(self, flags, blocking):
+               if self.fd == None:
+                       self._acquire_fd()
+               # we do it this way, due to the fact try/except is a bit of a 
hit
+               if not blocking:
+                       try:    fcntl.flock(self.fd, flags|fcntl.LOCK_NB)
+                       except IOError, ie:
+                               if ie.errno == 11:
+                                       return False
+                               raise GenericFailed(self.path, ie)
+               else:
+                       fcntl.flock(self.fd, flags)
+               return True
+
+       def acquire_write_lock(self, blocking=True):
+               """Acquire an exclusive lock
+               Returns True if lock is acquired, False if not.
+               Note if you have a read lock, it implicitly upgrades 
atomically"""
+               return self._enact_change(fcntl.LOCK_EX, blocking)
+
+       def acquire_read_lock(self, blocking=True):
+               """Acquire a shared lock
+               Returns True if lock is acquired, False if not.
+               Note, if you have a write_lock already, it'll implicitly 
downgrade atomically"""
+               return self._enact_change(fcntl.LOCK_SH, blocking)
+       
+       def release_write_lock(self):
+               """Release an exclusive lock if held"""
+               self._enact_change(fcntl.LOCK_UN, False)
+               
+       def release_read_lock(self):
+               self._enact_change(fcntl.LOCK_UN, False)
+
+       def __del__(self):
+               # alright, it's 5:45am, yes this is weird code.
+               try:
+                       if self.fd != None:
+                               self.release_read_lock()
+               finally:
+                       if self.fd != None:
+                               os.close(self.fd)
+
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_modules.py ./pym/portage_modules.py
--- /usr/lib/portage/pym/portage_modules.py     1969-12-31 19:00:00.000000000 
-0500
+++ ./pym/portage_modules.py    2005-11-15 23:18:15.086870984 -0500
@@ -0,0 +1,52 @@
+# Copyright: 2005 Gentoo Foundation
+# License: GPL2
+# $Id: modules.py 2284 2005-11-10 00:35:50Z ferringb $
+
+import sys, threading
+
+class FailedImport(ImportError):
+       def __init__(self, trg, e):     self.trg, self.e = trg, e
+       def __str__(self):      return "Failed importing target '%s': '%s'" % 
(self.trg, self.e)
+
+__import_lock = threading.Lock()
+
+def load_module(name):
+       """load a module, throwing a FailedImport if __import__ fails"""
+       __import_lock.acquire()
+       try:
+               if name in sys.modules:
+                       return sys.modules[name]
+               try:
+                       m = __import__(name)
+                       nl = name.split('.')
+                       # __import__ returns nl[0]... so.
+                       nl.pop(0)
+                       while len(nl):
+                               m = getattr(m, nl[0])
+                               nl.pop(0)
+                       return m
+               # * ferringb|afk hit it at some point, sure of that
+               # but no idea how, so commenting out to see if things break...
+               # except AttributeError, e:
+               #       raise FailedImport(name, e)
+               except ImportError, e:
+                       try:
+                               del sys.modules[name]
+                       except KeyError:
+                               pass
+                       raise FailedImport(name, e)
+       finally:
+               __import_lock.release()
+
+def load_attribute(name):
+       """load a specific attribute, rather then a module"""
+       try:
+               i = name.rfind(".")
+               if i == -1:
+                       raise ValueError("name isn't an attribute, it's a 
module... : %s" % name)
+               m = load_module(name[:i])
+               m = getattr(m, name[i+1:])
+               return m
+       except (AttributeError, ImportError), e:
+               raise FailedImport(name, e)
+
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_plugins.py ./pym/portage_plugins.py
--- /usr/lib/portage/pym/portage_plugins.py     1969-12-31 19:00:00.000000000 
-0500
+++ ./pym/portage_plugins.py    2005-11-15 23:51:02.883720392 -0500
@@ -0,0 +1,174 @@
+# Copyright: 2005 Gentoo Foundation
+# License: GPL2
+# $Id:$
+
+# I don't like this.
+# doesn't seem clean/right.
+
+import os
+from portage_const import PLUGINS_DIR
+from portage_locks import FsLock, NonExistant
+from portage_file import ensure_dirs
+from portage_data import portage_gid, root_uid
+from ConfigParser import RawConfigParser
+from portage_modules import load_attribute
+
+
+PLUGINS_EXTENSION = ".plugins"
+
+class RegistrationException(Exception):
+       def __init__(self, reason):             self.reason = reason
+       def __str__(self):      return "failed action due to %s" % self.reason
+       
+class FailedDir(RegistrationException):
+       pass
+       
+class PluginExistsAlready(RegistrationException):
+       def __init__(self):
+               RegistrationException.__init__(self, "plugin exists aleady, 
magic found")
+
+class FailedUpdating(RegistrationException):
+       def __str__(self):
+               return "failed updating plugin_type due error: %s" % 
(self.reason)
+
+class PluginNotFound(RegistrationException):
+       def __init__(self, plugin, reason="unknown"):
+               self.plugin, self.reason = plugin, reason
+       def __str__(self):
+               return "Plugin '%s' wasn't found; reason: %s" % (self.plugin, 
self.reason)
+
+
+class GlobalPluginRegistry(object):
+       def register(self, plugin_type, magic, version, namespace, 
replace=False):
+               """register a plugin
+               plugin_type is a string, the category of the plugin
+               magic is a string, magic constant of the plugin
+               version is the specific plugin version (only one can be 
installed at a time)
+               namespace is the pythonic namespace for that plugin
+               replace controls whether or not a plugin_type + magic conflict 
will be replaced, or error out"""
+               if not ensure_dirs(PLUGINS_DIR, uid=root_uid, gid=portage_gid, 
mode=0755):
+                       raise FailedDir("Failed ensuring base plugins dir")
+
+               # this could be fine grained down to per plugin_type
+               plug_lock = FsLock(plugins_dir)
+               plug_lock.acquire_write_lock()
+               try:
+                       ptype_fp = os.path.join(plugins_dir, 
plugin_type.lstrip(os.path.sep) + PLUGINS_EXTENSION)
+                       existing = self.query_plugins(plugin_type, 
locking=False, raw=True)
+                       if existing.has_section(magic):
+                               if not replace:
+                                       raise PluginExistsAlready()
+                               existing.remove_section(magic)
+                       existing.add_section(magic)
+                       existing.set(magic, "version", version)
+                       existing.set(magic, "namespace", namespace)
+                       try:
+                               f = open(ptype_fp, "w")
+                               os.chmod(ptype_fp, 0644)
+                               os.chown(ptype_fp, root_uid, portage_gid)
+                               existing.write(f)
+                               f.close()
+                       except OSError, oe:
+                               raise FailedUpdating(oe)
+
+               finally:
+                       plug_lock.release_write_lock()
+       
+       def deregister(self, plugin_type, magic, version, ignore_errors=False):
+               """plugin_type is the categorization of the plugin
+               magic is the magic constant for lookup
+               version is the version of the plugin to yank
+               ignore_errors controls whether or not an exception is thrown 
when the plugin isn't found"""
+               plug_lock = FsLock(plugins_dir)
+               plug_lock.acquire_write_lock()
+               try:
+                       ptype_fp = os.path.join(plugins_dir, 
plugin_type.lstrip(os.path.sep) + PLUGINS_EXTENSION)
+                       existing = self.query_plugins(locking=False, raw=True)
+                       if plugin_type not in existing:
+                               if ignore_errors:       return
+                               raise PluginNotFound(magic, "no plugin type")
+
+                       existing = existing[plugin_type]
+                       if not existing.has_section(magic):
+                               if ignore_errors:       return
+                               raise PluginNotFound(magic, "magic not found in 
plugin_type")
+                               
+                       if not existing.has_option(magic, "version") or 
str(version) != existing.get(magic, "version"):
+                               if ignore_errors: return
+                               raise PluginNotFound(magic, "version not found 
in plugin_type")
+                       
+                       existing.remove_section(magic)
+                       try:
+                               if len(existing.sections()) == 0:
+                                       os.unlink(ptype_fp)
+                               else:
+                                       f = open(ptype_fp, "w")
+                                       os.chmod(ptype_fp, 0644)
+                                       os.chown(ptype_fp, root_uid, 
portage_gid)
+                                       existing.write(f)
+                                       f.close()
+                       except OSError, oe:
+                               raise FailedUpdating(oe)
+
+               finally:
+                       plug_lock.release_write_lock()
+
+       def get_plugin(self, plugin_type, magic):
+               try:    address = 
self.query_plugins(plugin_type)[magic]["namespace"]
+               except KeyError:
+                       raise PluginNotFound(magic)
+               return load_attribute(address)
+
+       def query_plugins(self, plugin_type=None, locking=True, raw=False):
+               # designed this way to minimize lock holding time.
+               if plugin_type != None:
+                       ptypes = [plugin_type + PLUGINS_EXTENSION]
+               d = {}
+               if locking:
+                       try:
+                               plug_lock = FsLock(plugins_dir)
+                       except NonExistant:
+                               return {}
+                       plug_lock.acquire_read_lock()
+               try:
+                       if plugin_type == None:
+                               ptypes = [x for x in os.listdir(plugins_dir) if 
x.endswith(PLUGINS_EXTENSION) ]
+       
+                       len_exten = len(PLUGINS_EXTENSION)
+                       for x in ptypes:
+                               c = RawConfigParser()
+                               c.read(os.path.join(plugins_dir, 
x.lstrip(os.path.sep)))
+                               if raw:
+                                       d[x[:-len_exten]] = c
+                               else:
+                                       d[x[:-len_exten]] = dict([(y, 
dict(c.items(y))) for y in c.sections()])
+               
+               finally:
+                       if locking:
+                               plug_lock.release_read_lock()
+               if plugin_type != None:
+                       return d[plugin_type]
+               return d
+
+
+registry = None
+from portage.util.currying import pre_curry, pretty_docs
+
+def proxy_it(method, *a, **kw):
+       global registry
+       if registry == None:
+               registry = GlobalPluginRegistry()
+       return getattr(registry, method)(*a, **kw)
+
+for x in ["register", "deregister", "query_plugins", "get_plugin"]:
+       v = pre_curry(proxy_it, x)
+       doc = getattr(GlobalPluginRegistry, x).__doc__
+       if doc == None:
+               doc = ''
+       else:
+               # do this so indentation on pydoc __doc__ is sane
+               doc = "\n".join(map(lambda x:x.lstrip(), doc.split("\n"))) +"\n"
+       doc += "proxied call to module level registry instances %s method" % x
+       globals()[x] = pretty_docs(v, doc)
+
+del x, v, proxy_it, doc
diff -Nru --exclude portage-plugins-backport.patch --exclude '*.pyc' --exclude 
'*.pyo' /usr/lib/portage/pym/portage_util.py ./pym/portage_util.py
--- /usr/lib/portage/pym/portage_util.py        2005-11-15 23:52:28.957635168 
-0500
+++ ./pym/portage_util.py       2005-11-15 23:13:18.016032616 -0500
@@ -5,10 +5,9 @@
 
 import sys,string,shlex,os.path
 
-noiselimit = 0
 def writemsg(mystr,noiselevel=0):
        """Prints out warning and debug messages based on the noiselimit 
setting"""
-       global noiselimit
+       noiselimit = 0
        if noiselevel <= noiselimit:
                sys.stderr.write(mystr)
                sys.stderr.flush()
@@ -274,8 +273,8 @@
        return mykeys
        
 #cache expansions of constant strings
-cexpand={}
 def varexpand(mystring,mydict={}):
+       cexpand={}
        try:
                return cexpand[" "+mystring]
        except KeyError:

Reply via email to