[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