[yum-cvs] yum/yum plugins.py,1.1,1.2
Menno Smits
mjs at login.linux.duke.edu
Fri Mar 25 09:47:30 UTC 2005
Update of /home/groups/yum/cvs/yum/yum
In directory login:/tmp/cvs-serv15664/yum
Modified Files:
plugins.py
Log Message:
Plugins now have a general config file at /etc/yum/plugins.conf.
Each plugin also has a config file at /etc/yum/pluginconf.d/<pluginname>.conf.
Added methods to PluginConduit to allow retrieval of plugin specific options.
Index: plugins.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/plugins.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- plugins.py 21 Mar 2005 12:37:13 -0000 1.1
+++ plugins.py 25 Mar 2005 09:47:28 -0000 1.2
@@ -4,6 +4,11 @@
import imp
import atexit
from constants import *
+import ConfigParser
+import config
+import Errors
+
+# TODO: rename PLUG_OPT_WHERE_GLOBAL - > PLUG_OPT_WHERE_MAIN
# TODO: API version checking
# - multiversion plugin support?
@@ -12,9 +17,6 @@
# to hook into something that it doesn't support (eg. new plugin with older yum
# version)
-# TODO: move all config hooks to within yum pacakge (not cli.py). This may
-# require some minor refactoring of various yum bits.
-
# TODO: better documentation of how the whole thing works (esp. addition of
# config options)
@@ -26,7 +28,7 @@
# TODO: reposetup slot: plugin must be able to enable and disable repos
-# TODO: make it that plugins need to be expicity enabled so that software using
+# TODO: make it that plugins need to be explicitly enabled so that software using
# yum as a library doesn't get expected plugin interference?
# TODO: cmd line options to disable plugins (all or specific)
@@ -50,13 +52,17 @@
# TODO: require an explicit call to load plugins so that software using yum as
# a # library doesn't get nasty suprises
-SLOTS = ('config', 'init', 'exclude', 'pretrans', 'posttrans', 'close')
+PLUGINS_CONF = '/etc/yum/plugins.conf'
+SLOTS = ('config', 'init', 'exclude', 'pretrans', 'posttrans', 'close')
class YumPlugins:
- def __init__(self, base, dir):
- self.dir = dir
+ def __init__(self, base):
+ self.enabled = 0
+ self.searchpath = ['/usr/lib/yum-plugins']
self.base = base
+
+ self._getglobalconf()
self._importplugins()
self.opts = []
@@ -66,29 +72,58 @@
# Let plugins register custom config file options
self.run('config')
+ def _getglobalconf(self):
+ '''Read global plugin configuration
+ '''
+ parser = config.CFParser()
+ try:
+ fin = open(PLUGINS_CONF, 'rt')
+ parser.readfp(fin)
+ fin.close()
+ except ConfigParser.Error, e:
+ raise Errors.ConfigError("Couldn't parse %s: %s" % (PLUGINS_CONF,
+ str(e)))
+
+ except IOError, e:
+ self.base.log(3, "Couldn't read %s: plugins disabled" % PLUGINS_CONF)
+ return
+
+ self.enabled = parser._getboolean('main', 'enabled', 0)
+ searchpath = parser._getoption('main', 'searchpath', '')
+ if searchpath:
+ self.searchpath = config.parseList(searchpath)
+ # Ensure that all search paths are absolute
+ for path in self.searchpath:
+ if path[0] != '/':
+ raise Errors.ConfigError(
+ "All plugin search paths must be absolute")
+
def run(self, slotname):
'''Run all plugin functions for the given slot.
Returns true if yum needs to quit, false otherwise.
'''
+ if not self.enabled:
+ return 0
# Determine handler class to use
if slotname in ('config'):
- gwcls = ConfigPluginConduit
+ conduitcls = ConfigPluginConduit
elif slotname == 'init':
- gwcls = InitPluginConduit
+ conduitcls = InitPluginConduit
elif slotname == 'close':
- gwcls = PluginConduit
+ conduitcls = PluginConduit
elif slotname in ('pretrans', 'posttrans', 'exclude'):
- gwcls = MainPluginConduit
+ conduitcls = MainPluginConduit
else:
raise ValueError('unknown slot name "%s"' % slotname)
- gw = gwcls(self, self.base)
for modname, func in self._pluginfuncs[slotname]:
self.base.log(4, 'Running %s handler for %s plugin' % (
slotname, modname))
- result = func(gw)
+
+ _, conf = self._plugins[modname]
+ result = func(conduitcls(self, self.base, conf))
if result:
# Plugin said we need to terminate
self.base.log(2, "Exiting due to '%s' plugin." % modname)
@@ -97,30 +132,71 @@
def _importplugins(self):
+ if not self.enabled:
+ return 0
+
# Initialise plugin dict
self._plugins = {}
self._pluginfuncs = {}
for slot in SLOTS:
self._pluginfuncs[slot] = []
- # Import plugins and collect plugin calls for each slot
- for module in glob.glob('%s/*.py' % self.dir):
- modname = os.path.basename(module).split('.py')[0]
-
- self.base.log(2, 'Loading %s plugin' % modname)
-
- fp, pathname, description = imp.find_module(modname, [self.dir])
- module = imp.load_module(modname, fp, pathname, description)
-
- #TODO: check API version here?
-
- self._plugins[modname] = module
-
- for slot in SLOTS:
- if hasattr(module, slot):
- self._pluginfuncs[slot].append(
- (modname, getattr(module, slot))
- )
+ # Import plugins
+ for dir in self.searchpath:
+ if not os.path.isdir(dir):
+ continue
+ for modulefile in glob.glob('%s/*.py' % dir):
+ self._loadplugin(modulefile)
+
+ def _loadplugin(self, modulefile):
+ '''Attempt to import a plugin module and register the hook methods it
+ uses.
+ '''
+ dir, modname = os.path.split(modulefile)
+ modname = modname.split('.py')[0]
+
+ conf = self._getpluginconf(modname)
+ if not conf or not conf._getboolean('main', 'enabled', 0):
+ self.base.log(2, '"%s" plugin is disabled' % modname)
+ return
+
+ self.base.log(2, 'Loading "%s" plugin' % modname)
+
+ fp, pathname, description = imp.find_module(modname, [dir])
+ module = imp.load_module(modname, fp, pathname, description)
+
+ #TODO: check API version here?
+
+ if not self._plugins.has_key(modname):
+ self._plugins[modname] = (module, conf)
+ else:
+ raise Errors.ConfigError('Two or more plugins with the name "%s" ' \
+ 'exist in the plugin search path' % modname)
+
+ for slot in SLOTS:
+ if hasattr(module, slot):
+ self._pluginfuncs[slot].append((modname, getattr(module, slot)))
+
+ def _getpluginconf(self, modname):
+ '''Parse the plugin specific configuration file and return a CFParser
+ instance representing it. Returns None if there was an error reading or
+ parsing the configuration file.
+ '''
+ conffilename = os.path.join('/etc/yum/pluginconf.d', modname+'.conf')
+
+ parser = config.CFParser()
+ try:
+ fin = open(conffilename, 'rt')
+ parser.readfp(fin)
+ fin.close()
+ except ConfigParser.Error, e:
+ raise Errors.ConfigError("Couldn't parse %s: %s" % (conffilename,
+ str(e)))
+ except IOError, e:
+ self.base.log(2, str(e))
+ return None
+
+ return parser
def registeropt(self, name, valuetype, where, default):
'''Called from plugins to register a new config file option.
@@ -149,9 +225,10 @@
return out
class PluginConduit:
- def __init__(self, parent, base):
+ def __init__(self, parent, base, conf):
self._parent = parent
self._base = base
+ self._conf = conf
def info(self, level, msg):
self._base.log(level, msg)
@@ -166,6 +243,26 @@
else:
return self._base.userconfirm()
+ def getconfstring(self, section, opt, default=None):
+ '''Read a string value from the plugin's own configuration file
+ '''
+ return self._conf._getoption(section, opt, default)
+
+ def getconfint(self, section, opt, default=None):
+ '''Read an integer value from the plugin's own configuration file
+ '''
+ return self._conf._getint(section, opt, default)
+
+ def getconffloat(self, section, opt, default=None):
+ '''Read a float value from the plugin's own configuration file
+ '''
+ return self._conf._getfloat(section, opt, default)
+
+ def getconfbool(self, section, opt, default=None):
+ '''Read a boolean value from the plugin's own configuration file
+ '''
+ return self._conf._getboolean(section, opt, default)
+
class ConfigPluginConduit(PluginConduit):
def registeropt(self, *args, **kwargs):
More information about the Yum-cvs-commits
mailing list