[yum-cvs] yum/yum __init__.py, 1.103, 1.104 config.py, 1.56, 1.57 constants.py, 1.2, 1.3 plugins.py, 1.2, 1.3
Menno Smits
mjs at login.linux.duke.edu
Sun Mar 27 03:22:00 UTC 2005
Update of /home/groups/yum/cvs/yum/yum
In directory login:/tmp/cvs-serv10595
Modified Files:
__init__.py config.py constants.py plugins.py
Log Message:
Lots of plugin related changes:
- API versioning
- cleaned up API somewhat
- hook methods now need a "_hook" suffix. This will allow detection of
plugins that are trying to register hooks that aren't supported.
- plugin hook method return codes are now ignored. Plugins should now use
PluginYumExit exception if yum should terminate.
- started reposetup hook
- custom option conflict detection
- renamed PLUG_OPT_WHERE_GLOBAL to PLUG_OPT_WHERE_MAIN
Index: __init__.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/__init__.py,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -r1.103 -r1.104
--- __init__.py 26 Mar 2005 07:54:15 -0000 1.103
+++ __init__.py 27 Mar 2005 03:21:57 -0000 1.104
@@ -77,8 +77,7 @@
self.getReposFromConfig()
# Initialise plugins
- if self.plugins.run('init') != 0:
- sys.exit()
+ self.plugins.run('init')
def getReposFromConfig(self):
"""read in repositories from config main and .repo files"""
@@ -132,7 +131,7 @@
except Errors.RepoError, e:
self.errorlog(2, e)
continue
-
+
def doTsSetup(self):
"""setup all the transaction set storage items we'll need
This can't happen in __init__ b/c we don't know our installroot
@@ -194,7 +193,6 @@
self.errorlog(0, str(e))
raise
-
def doSackSetup(self, archlist=None):
"""populates the package sacks for information from our repositories,
takes optional archlist for archs to include"""
@@ -215,8 +213,7 @@
for repo in self.repos.listEnabled():
self.excludePackages(repo)
self.includePackages(repo)
- if self.plugins.run('exclude') != 0:
- sys.exit()
+ self.plugins.run('exclude')
self.pkgSack.buildIndexes()
def doUpdateSetup(self):
@@ -293,8 +290,7 @@
def runTransaction(self, cb):
"""takes an rpm callback object, performs the transaction"""
- if self.plugins.run('pretrans') != 0:
- return
+ self.plugins.run('pretrans')
errors = self.ts.run(cb.callback, '')
if errors:
@@ -304,8 +300,7 @@
raise yum.Errors.YumBaseError, errstring
- if self.plugins.run('posttrans') != 0:
- return
+ self.plugins.run('posttrans')
def excludePackages(self, repo=None):
"""removes packages from packageSacks based on global exclude lists,
Index: config.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/config.py,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -r1.56 -r1.57
--- config.py 26 Mar 2005 18:28:25 -0000 1.56
+++ config.py 27 Mar 2005 03:21:57 -0000 1.57
@@ -335,7 +335,7 @@
setattr(self, option, self.configdata[option])
# Process options from plugins
- dopluginopts(self.plugins, self.cfg, 'main', PLUG_OPT_WHERE_GLOBAL,
+ dopluginopts(self.plugins, self.cfg, 'main', PLUG_OPT_WHERE_MAIN,
self.setConfigOption)
def listConfigOptions(self):
Index: constants.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/constants.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- constants.py 21 Mar 2005 12:37:13 -0000 1.2
+++ constants.py 27 Mar 2005 03:21:57 -0000 1.3
@@ -45,7 +45,7 @@
PLUG_OPT_FLOAT = 2
PLUG_OPT_BOOL = 3
-PLUG_OPT_WHERE_GLOBAL = 0
+PLUG_OPT_WHERE_MAIN = 0
PLUG_OPT_WHERE_REPO = 1
PLUG_OPT_WHERE_ALL = 2
Index: plugins.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/plugins.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- plugins.py 25 Mar 2005 09:47:28 -0000 1.2
+++ plugins.py 27 Mar 2005 03:21:57 -0000 1.3
@@ -8,28 +8,29 @@
import config
import Errors
-# TODO: rename PLUG_OPT_WHERE_GLOBAL - > PLUG_OPT_WHERE_MAIN
-
-# TODO: API version checking
-# - multiversion plugin support?
+# TODO: fix log() during yum init: early calls to log() (before Logger instance
+# is created) mean that all output goes to stdout regardless of the log settings.
+# - peek at debuglevel option?
-# TODO: prefix for slot methods ("yum_"?) so that yum knows if plugin is trying
-# to hook into something that it doesn't support (eg. new plugin with older yum
-# version)
+# TODO: finish reposetup slot: where to call from?
# TODO: better documentation of how the whole thing works (esp. addition of
# config options)
+# - document from user perspective in yum man page
+# - PLUGINS.txt for developers
-# TODO: use exception in plugins to signal that yum should abort instead of
-# return codes
+# TODO: require an explicit call to load plugins so that software using yum as
+# a library doesn't get nasty suprises
-# TODO: fix log() during yum init: early calls to log() (before Logger instance
-# is created) mean that all output goes to stdout regardless of the log settings.
+# TODO: check for *_hook methods that aren't supported
-# TODO: reposetup slot: plugin must be able to enable and disable repos
+# TODO "log" slot? To allow plugins to do customised logging/history (say to a
+# SQL db)
-# 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: method for plugins to retrieve running yum version (move __version__ to
+# yum/__init__.py?)
+
+# TODO: multiversion plugin support
# TODO: cmd line options to disable plugins (all or specific)
@@ -38,23 +39,39 @@
# TODO: config vars marked as PLUG_OPT_WHERE_ALL should inherit defaults from
# the [main] setting if the user doesn't specify them
-# TODO: handling of plugins that define options which collide with other
-# plugins or builtin yum options
-
# TODO: plugins should be able to specify convertor functions for config vars
# TODO: investigate potential issues with plugins doing user output during
# their close handlers, esp wrt GUI apps
-# TODO "log" slot? To allow plugins to do customised logging/history (say to a
-# SQL db)
+# TODO: detect conflicts between builtin yum options and registered plugin
+# options (will require refactoring of config.py)
-# TODO: require an explicit call to load plugins so that software using yum as
-# a # library doesn't get nasty suprises
+
+# The API_VERSION constant defines the current plugin API version. It is used
+# to decided whether or not plugins can be loaded. It is compared against the
+# 'requires_api_version' attribute of each plugin. The version number has the
+# format: "major_version.minor_version".
+#
+# For a plugin to be loaded the major version required by the plugin must match
+# the major version in API_VERSION. Additionally, the minor version in
+# API_VERSION must be greater than or equal the minor version required by the
+# plugin.
+#
+# If a change to yum is made that break backwards compatibility wrt the plugin
+# API, the major version number must be incremented and the minor version number
+# reset to 0. If a change is made that doesn't break backwards compatibility,
+# then the minor number must be incremented.
+API_VERSION = '0.2'
PLUGINS_CONF = '/etc/yum/plugins.conf'
+SLOTS = ('config', 'init', 'reposetup', 'exclude', 'pretrans', 'posttrans',
+ 'close')
+
+class PluginYumExit(Errors.YumBaseError):
+ '''Used by plugins to signal that yum should stop
+ '''
-SLOTS = ('config', 'init', 'exclude', 'pretrans', 'posttrans', 'close')
class YumPlugins:
def __init__(self, base):
@@ -64,7 +81,7 @@
self._getglobalconf()
self._importplugins()
- self.opts = []
+ self.opts = {}
# Call close handlers when yum exit's
atexit.register(self.run, 'close')
@@ -110,6 +127,8 @@
conduitcls = ConfigPluginConduit
elif slotname == 'init':
conduitcls = InitPluginConduit
+ elif slotname == 'reposetup':
+ conduitcls = RepoSetupPluginConduit
elif slotname == 'close':
conduitcls = PluginConduit
elif slotname in ('pretrans', 'posttrans', 'exclude'):
@@ -165,8 +184,20 @@
fp, pathname, description = imp.find_module(modname, [dir])
module = imp.load_module(modname, fp, pathname, description)
- #TODO: check API version here?
+ # Check API version required by the plugin
+ if not hasattr(module, 'requires_api_version'):
+ raise Errors.ConfigError(
+ 'Plugin "%s" doesn\'t specify required API version' % modname
+ )
+ if not apiverok(API_VERSION, module.requires_api_version):
+ raise Errors.ConfigError(
+ 'Plugin "%s" requires API %s. Supported API is %s.' % (
+ modname,
+ module.requires_api_version,
+ API_VERSION,
+ ))
+ # Store the plugin module and its configuration file
if not self._plugins.has_key(modname):
self._plugins[modname] = (module, conf)
else:
@@ -174,8 +205,11 @@
'exist in the plugin search path' % modname)
for slot in SLOTS:
- if hasattr(module, slot):
- self._pluginfuncs[slot].append((modname, getattr(module, slot)))
+ funcname = slot+'_hook'
+ if hasattr(module, funcname):
+ self._pluginfuncs[slot].append(
+ (modname, getattr(module, funcname))
+ )
def _getpluginconf(self, modname):
'''Parse the plugin specific configuration file and return a CFParser
@@ -204,22 +238,25 @@
name: Name of the new option.
valuetype: Option type (PLUG_OPT_BOOL, PLUG_OPT_STRING ...)
where: Where the option should be available in the config file.
- (PLUG_OPT_WHERE_GLOBAL, PLUG_OPT_WHERE_REPO, ...)
+ (PLUG_OPT_WHERE_MAIN, PLUG_OPT_WHERE_REPO, ...)
default: Default value for the option if not set by the user.
'''
- #TODO: duplicate detection
- self.opts.append((name, valuetype, where, default))
+ if self.opts.has_key(name):
+ raise Errors.ConfigError('Plugin option conflict: ' \
+ 'an option named "%s" has already been registered' % name
+ )
+ self.opts[name] = (valuetype, where, default)
def getopts(self, targetwhere):
'''Retrieve plugin defined options for the given part of the
configuration file.
targetwhere: the type of option wanted. Should be
- PLUG_OPT_WHERE_GLOBAL, PLUG_OPT_WHERE_REPO or PLUG_OPT_WHERE_ALL
+ PLUG_OPT_WHERE_MAIN, PLUG_OPT_WHERE_REPO or PLUG_OPT_WHERE_ALL
return: A list of (name, value_type, default) tuples.
'''
out = []
- for name, valuetype, where, default in self.opts:
+ for name, (valuetype, where, default) in self.opts.iteritems():
if where == targetwhere or where == PLUG_OPT_WHERE_ALL:
out.append((name, valuetype, default))
return out
@@ -236,36 +273,36 @@
def error(self, level, msg):
self._base.errorlog(level, msg)
- def promptyn(self, msg):
+ def promptYN(self, msg):
self.info(2, msg)
if self._base.conf.getConfigOption('assumeyes'):
return 1
else:
return self._base.userconfirm()
- def getconfstring(self, section, opt, default=None):
+ def confString(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):
+ def confInt(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):
+ def confFloat(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):
+ def confBool(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):
+ def registerOpt(self, *args, **kwargs):
self._parent.registeropt(*args, **kwargs)
class InitPluginConduit(PluginConduit):
@@ -273,10 +310,12 @@
def getConf(self):
return self._base.conf
-class MainPluginConduit(InitPluginConduit):
+class RepoSetupPluginConduit(InitPluginConduit):
- def getRepos(self):
- return self._base.repos.listEnabled()
+ def getRepos(self, pattern='*'):
+ return self._base.repos.findRepos(pattern)
+
+class MainPluginConduit(RepoSetupPluginConduit):
def getPackages(self, repo=None):
if repo:
@@ -291,6 +330,23 @@
def getTsInfo(self):
return self._base.tsInfo
+def parsever(apiver):
+ maj, min = apiver.split('.')
+ return int(maj), int(min)
+
+def apiverok(a, b):
+ '''Return true if API version "a" supports API version "b"
+ '''
+ a = parsever(a)
+ b = parsever(b)
+
+ if a[0] != b[0]:
+ return 0
+
+ if a[1] >= b[1]:
+ return 1
+
+ return 0
More information about the Yum-cvs-commits
mailing list